uploadcare-ruby 4.4.3 → 5.0.0.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 (178) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +7 -0
  3. data/.github/workflows/gem-push.yml +1 -1
  4. data/.github/workflows/ruby.yml +10 -13
  5. data/.gitignore +9 -0
  6. data/.rubocop.yml +95 -8
  7. data/CHANGELOG.md +71 -1
  8. data/Gemfile +23 -6
  9. data/MIGRATING_V5.md +290 -0
  10. data/README.md +422 -671
  11. data/Rakefile +5 -1
  12. data/api_examples/README.md +77 -0
  13. data/api_examples/rest_api/delete_files_storage.rb +3 -5
  14. data/api_examples/rest_api/delete_files_uuid_metadata_key.rb +3 -4
  15. data/api_examples/rest_api/delete_files_uuid_storage.rb +3 -4
  16. data/api_examples/rest_api/delete_groups_uuid.rb +3 -4
  17. data/api_examples/rest_api/delete_webhooks_unsubscribe.rb +3 -4
  18. data/api_examples/rest_api/get_addons_aws_rekognition_detect_labels_execute_status.rb +3 -6
  19. data/api_examples/rest_api/get_addons_aws_rekognition_detect_moderation_labels_execute_status.rb +3 -6
  20. data/api_examples/rest_api/get_addons_remove_bg_execute_status.rb +3 -6
  21. data/api_examples/rest_api/get_addons_uc_clamav_virus_scan_execute_status.rb +3 -6
  22. data/api_examples/rest_api/get_convert_document_status_token.rb +3 -5
  23. data/api_examples/rest_api/get_convert_document_uuid.rb +3 -5
  24. data/api_examples/rest_api/get_convert_video_status_token.rb +3 -5
  25. data/api_examples/rest_api/get_files.rb +3 -5
  26. data/api_examples/rest_api/get_files_uuid.rb +3 -5
  27. data/api_examples/rest_api/get_files_uuid_metadata.rb +3 -5
  28. data/api_examples/rest_api/get_files_uuid_metadata_key.rb +3 -5
  29. data/api_examples/rest_api/get_groups.rb +3 -5
  30. data/api_examples/rest_api/get_groups_uuid.rb +3 -5
  31. data/api_examples/rest_api/get_project.rb +3 -5
  32. data/api_examples/rest_api/get_webhooks.rb +3 -5
  33. data/api_examples/rest_api/post_addons_aws_rekognition_detect_labels_execute.rb +3 -5
  34. data/api_examples/rest_api/post_addons_aws_rekognition_detect_moderation_labels_execute.rb +3 -5
  35. data/api_examples/rest_api/post_addons_remove_bg_execute.rb +3 -5
  36. data/api_examples/rest_api/post_addons_uc_clamav_virus_scan_execute.rb +3 -5
  37. data/api_examples/rest_api/post_convert_document.rb +3 -8
  38. data/api_examples/rest_api/post_convert_video.rb +3 -10
  39. data/api_examples/rest_api/post_files_local_copy.rb +3 -6
  40. data/api_examples/rest_api/post_files_remote_copy.rb +3 -7
  41. data/api_examples/rest_api/post_webhooks.rb +3 -9
  42. data/api_examples/rest_api/put_files_storage.rb +3 -8
  43. data/api_examples/rest_api/put_files_uuid_metadata_key.rb +3 -7
  44. data/api_examples/rest_api/put_files_uuid_storage.rb +3 -5
  45. data/api_examples/rest_api/put_webhooks_id.rb +3 -11
  46. data/api_examples/support/example_helper.rb +250 -0
  47. data/api_examples/support/run_rest_example.rb +161 -0
  48. data/api_examples/support/run_upload_example.rb +88 -0
  49. data/api_examples/upload_api/get_from_url_status.rb +3 -5
  50. data/api_examples/upload_api/get_group_info.rb +3 -6
  51. data/api_examples/upload_api/get_info.rb +3 -6
  52. data/api_examples/upload_api/post_base.rb +3 -5
  53. data/api_examples/upload_api/post_from_url.rb +3 -5
  54. data/api_examples/upload_api/post_group.rb +3 -8
  55. data/api_examples/upload_api/post_multipart_complete.rb +3 -7
  56. data/api_examples/upload_api/post_multipart_start.rb +3 -7
  57. data/api_examples/upload_api/put_multipart_part.rb +4 -0
  58. data/bin/console +1 -1
  59. data/docs/release-notes-5.0.0.rc1.md +34 -0
  60. data/examples/README.md +39 -0
  61. data/examples/batch_upload.rb +54 -0
  62. data/examples/group_creation.rb +88 -0
  63. data/examples/large_file_upload.rb +88 -0
  64. data/examples/simple_upload.rb +39 -0
  65. data/examples/upload_with_progress.rb +84 -0
  66. data/examples/url_upload.rb +56 -0
  67. data/lib/uploadcare/api/rest/addons.rb +107 -0
  68. data/lib/uploadcare/api/rest/document_conversions.rb +65 -0
  69. data/lib/uploadcare/api/rest/file_metadata.rb +71 -0
  70. data/lib/uploadcare/api/rest/files.rb +112 -0
  71. data/lib/uploadcare/api/rest/groups.rb +49 -0
  72. data/lib/uploadcare/api/rest/project.rb +23 -0
  73. data/lib/uploadcare/api/rest/video_conversions.rb +52 -0
  74. data/lib/uploadcare/api/rest/webhooks.rb +74 -0
  75. data/lib/uploadcare/api/rest.rb +254 -0
  76. data/lib/uploadcare/api/upload/files.rb +313 -0
  77. data/lib/uploadcare/api/upload/groups.rb +72 -0
  78. data/lib/uploadcare/api/upload.rb +272 -0
  79. data/lib/uploadcare/client/addons_accessor.rb +85 -0
  80. data/lib/uploadcare/client/api.rb +33 -0
  81. data/lib/uploadcare/client/conversions_accessor.rb +33 -0
  82. data/lib/uploadcare/client/document_conversions_accessor.rb +41 -0
  83. data/lib/uploadcare/client/file_metadata_accessor.rb +46 -0
  84. data/lib/uploadcare/client/files_accessor.rb +82 -0
  85. data/lib/uploadcare/client/groups_accessor.rb +35 -0
  86. data/lib/uploadcare/client/project_accessor.rb +17 -0
  87. data/lib/uploadcare/client/video_conversions_accessor.rb +33 -0
  88. data/lib/uploadcare/client/webhooks_accessor.rb +42 -0
  89. data/lib/uploadcare/client.rb +127 -0
  90. data/lib/uploadcare/cname_generator.rb +68 -0
  91. data/lib/uploadcare/collections/batch_result.rb +35 -0
  92. data/lib/uploadcare/collections/paginated.rb +165 -0
  93. data/lib/uploadcare/configuration.rb +81 -0
  94. data/lib/uploadcare/exception/auth_error.rb +2 -6
  95. data/lib/uploadcare/exception/configuration_error.rb +4 -0
  96. data/lib/uploadcare/exception/conversion_error.rb +2 -6
  97. data/lib/uploadcare/exception/invalid_request_error.rb +4 -0
  98. data/lib/uploadcare/exception/multipart_upload_error.rb +4 -0
  99. data/lib/uploadcare/exception/not_found_error.rb +4 -0
  100. data/lib/uploadcare/exception/request_error.rb +2 -6
  101. data/lib/uploadcare/exception/retry_error.rb +2 -6
  102. data/lib/uploadcare/exception/throttle_error.rb +7 -11
  103. data/lib/uploadcare/exception/unknown_status_error.rb +4 -0
  104. data/lib/uploadcare/exception/upload_error.rb +4 -0
  105. data/lib/uploadcare/exception/upload_timeout_error.rb +4 -0
  106. data/lib/uploadcare/internal/authenticator.rb +101 -0
  107. data/lib/uploadcare/internal/error_handler.rb +102 -0
  108. data/lib/uploadcare/internal/signature_generator.rb +31 -0
  109. data/lib/uploadcare/internal/throttle_handler.rb +36 -0
  110. data/lib/uploadcare/internal/upload_io.rb +110 -0
  111. data/lib/uploadcare/internal/upload_params_generator.rb +86 -0
  112. data/lib/uploadcare/internal/user_agent.rb +22 -0
  113. data/lib/uploadcare/operations/multipart_upload.rb +213 -0
  114. data/lib/uploadcare/operations/upload_router.rb +162 -0
  115. data/lib/uploadcare/resources/addon_execution.rb +97 -0
  116. data/lib/uploadcare/resources/base_resource.rb +61 -0
  117. data/lib/uploadcare/resources/document_conversion.rb +81 -0
  118. data/lib/uploadcare/resources/file.rb +366 -0
  119. data/lib/uploadcare/resources/file_metadata.rb +135 -0
  120. data/lib/uploadcare/resources/group.rb +142 -0
  121. data/lib/uploadcare/resources/project.rb +26 -0
  122. data/lib/uploadcare/resources/video_conversion.rb +59 -0
  123. data/lib/uploadcare/resources/webhook.rb +85 -0
  124. data/lib/uploadcare/result.rb +85 -0
  125. data/lib/uploadcare/signed_url_generators/akamai_generator.rb +50 -51
  126. data/lib/uploadcare/signed_url_generators/base_generator.rb +15 -15
  127. data/lib/uploadcare/version.rb +7 -0
  128. data/lib/uploadcare/webhook_signature_verifier.rb +60 -0
  129. data/lib/uploadcare.rb +84 -50
  130. data/mise.toml +2 -0
  131. data/uploadcare-ruby.gemspec +8 -7
  132. metadata +102 -74
  133. data/api_examples/upload_api/put_presigned_url_x.rb +0 -8
  134. data/lib/uploadcare/api/api.rb +0 -25
  135. data/lib/uploadcare/client/addons_client.rb +0 -69
  136. data/lib/uploadcare/client/conversion/base_conversion_client.rb +0 -60
  137. data/lib/uploadcare/client/conversion/document_conversion_client.rb +0 -45
  138. data/lib/uploadcare/client/conversion/video_conversion_client.rb +0 -46
  139. data/lib/uploadcare/client/file_client.rb +0 -48
  140. data/lib/uploadcare/client/file_list_client.rb +0 -46
  141. data/lib/uploadcare/client/file_metadata_client.rb +0 -36
  142. data/lib/uploadcare/client/group_client.rb +0 -45
  143. data/lib/uploadcare/client/multipart_upload/chunks_client.rb +0 -58
  144. data/lib/uploadcare/client/multipart_upload_client.rb +0 -64
  145. data/lib/uploadcare/client/project_client.rb +0 -20
  146. data/lib/uploadcare/client/rest_client.rb +0 -77
  147. data/lib/uploadcare/client/rest_group_client.rb +0 -43
  148. data/lib/uploadcare/client/upload_client.rb +0 -46
  149. data/lib/uploadcare/client/uploader_client.rb +0 -128
  150. data/lib/uploadcare/client/webhook_client.rb +0 -49
  151. data/lib/uploadcare/concern/error_handler.rb +0 -54
  152. data/lib/uploadcare/concern/throttle_handler.rb +0 -25
  153. data/lib/uploadcare/concern/upload_error_handler.rb +0 -32
  154. data/lib/uploadcare/entity/addons.rb +0 -14
  155. data/lib/uploadcare/entity/conversion/base_converter.rb +0 -43
  156. data/lib/uploadcare/entity/conversion/document_converter.rb +0 -15
  157. data/lib/uploadcare/entity/conversion/video_converter.rb +0 -15
  158. data/lib/uploadcare/entity/decorator/paginator.rb +0 -79
  159. data/lib/uploadcare/entity/entity.rb +0 -18
  160. data/lib/uploadcare/entity/file.rb +0 -103
  161. data/lib/uploadcare/entity/file_list.rb +0 -32
  162. data/lib/uploadcare/entity/file_metadata.rb +0 -30
  163. data/lib/uploadcare/entity/group.rb +0 -49
  164. data/lib/uploadcare/entity/group_list.rb +0 -24
  165. data/lib/uploadcare/entity/project.rb +0 -13
  166. data/lib/uploadcare/entity/uploader.rb +0 -93
  167. data/lib/uploadcare/entity/webhook.rb +0 -14
  168. data/lib/uploadcare/param/authentication_header.rb +0 -37
  169. data/lib/uploadcare/param/conversion/document/processing_job_url_builder.rb +0 -39
  170. data/lib/uploadcare/param/conversion/video/processing_job_url_builder.rb +0 -64
  171. data/lib/uploadcare/param/param.rb +0 -10
  172. data/lib/uploadcare/param/secure_auth_header.rb +0 -51
  173. data/lib/uploadcare/param/simple_auth_header.rb +0 -14
  174. data/lib/uploadcare/param/upload/signature_generator.rb +0 -24
  175. data/lib/uploadcare/param/upload/upload_params_generator.rb +0 -41
  176. data/lib/uploadcare/param/user_agent.rb +0 -21
  177. data/lib/uploadcare/param/webhook_signature_verifier.rb +0 -23
  178. data/lib/uploadcare/ruby/version.rb +0 -5
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Base class for all Uploadcare resource objects.
4
+ #
5
+ # Resources represent domain objects returned by the Uploadcare API.
6
+ # They hold attributes and a reference to the client that created them,
7
+ # enabling instance methods to make further API calls.
8
+ class Uploadcare::Resources::BaseResource
9
+ # @return [Uploadcare::Client] Client that created this resource
10
+ attr_reader :client
11
+
12
+ # @return [Uploadcare::Configuration] Configuration from the client
13
+ attr_reader :config
14
+
15
+ # Initialize a new resource with attributes and client context.
16
+ #
17
+ # @param attributes [Hash] API response attributes
18
+ # @param client_or_config [Uploadcare::Client, Uploadcare::Configuration, nil]
19
+ def initialize(attributes = {}, client_or_config = nil)
20
+ @client = self.class.resolve_client(client_or_config)
21
+ @config = @client.config
22
+ assign_attributes(attributes)
23
+ end
24
+
25
+ protected
26
+
27
+ # Assign hash attributes to instance variables via setter methods.
28
+ #
29
+ # @param attributes [Hash] Key-value pairs to assign
30
+ def assign_attributes(attributes)
31
+ attributes.each do |key, value|
32
+ setter = "#{key}="
33
+ public_send(setter, value) if respond_to?(setter)
34
+ end
35
+ end
36
+
37
+ class << self
38
+ # Resolve a client from various input types.
39
+ #
40
+ # @param client_or_config [Uploadcare::Client, Uploadcare::Configuration, nil]
41
+ # @param client [Uploadcare::Client, nil] Explicit client
42
+ # @param config [Uploadcare::Configuration] Configuration fallback
43
+ # @return [Uploadcare::Client]
44
+ def resolve_client(client_or_config = nil, client: nil, config: nil)
45
+ return client if client
46
+
47
+ case client_or_config
48
+ when Uploadcare::Client
49
+ client_or_config
50
+ when Uploadcare::Configuration
51
+ Uploadcare.client(config: client_or_config)
52
+ when nil
53
+ return Uploadcare.client(config: config) if config
54
+
55
+ raise ArgumentError, 'client or config is required'
56
+ else
57
+ raise ArgumentError, 'client or config is required'
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Document conversion resource.
4
+ #
5
+ # @see https://uploadcare.com/api-refs/rest-api/v0.7.0/#tag/Conversion
6
+ class Uploadcare::Resources::DocumentConversion < Uploadcare::Resources::BaseResource
7
+ attr_accessor :uuid, :error, :format, :converted_groups, :status, :result
8
+
9
+ # Get document format info and possible conversions.
10
+ #
11
+ # @param request_options [Hash] Request options
12
+ # @return [self]
13
+ def info(request_options: {})
14
+ raise ArgumentError, 'uuid is required' if uuid.to_s.empty?
15
+
16
+ response = Uploadcare::Result.unwrap(
17
+ client.api.rest.document_conversions.info(uuid: uuid, request_options: request_options)
18
+ )
19
+ assign_attributes(response)
20
+ self
21
+ end
22
+
23
+ # Convert a document to a specified format (class method).
24
+ #
25
+ # @param params [Hash] Conversion parameters (:uuid, :format)
26
+ # @param options [Hash] Optional parameters (:store, :save_in_group)
27
+ # @param client [Uploadcare::Client, nil] Client instance
28
+ # @param config [Uploadcare::Configuration] Configuration fallback
29
+ # @param request_options [Hash] Request options
30
+ # @return [Hash] Conversion response
31
+ def self.convert_document(params:, options: {}, client: nil, config: Uploadcare.configuration,
32
+ request_options: {})
33
+ resolved_client = resolve_client(client: client, config: config)
34
+ paths = Array(params[:uuid]).map do |uuid|
35
+ "#{uuid}/document/-/format/#{params[:format]}/"
36
+ end
37
+
38
+ Uploadcare::Result.unwrap(
39
+ resolved_client.api.rest.document_conversions.convert(
40
+ paths: paths, options: options, request_options: request_options
41
+ )
42
+ )
43
+ end
44
+
45
+ # Fetch document conversion status for a job token.
46
+ #
47
+ # @param token [String]
48
+ # @param client [Uploadcare::Client, nil]
49
+ # @param config [Uploadcare::Configuration]
50
+ # @param request_options [Hash]
51
+ # @return [Uploadcare::Resources::DocumentConversion]
52
+ def self.status(token:, client: nil, config: Uploadcare.configuration, request_options: {})
53
+ resolved_client = resolve_client(client: client, config: config)
54
+ new({}, resolved_client).fetch_status(token: token, request_options: request_options)
55
+ end
56
+
57
+ # Fetch document conversion capabilities for a file.
58
+ #
59
+ # @param uuid [String]
60
+ # @param client [Uploadcare::Client, nil]
61
+ # @param config [Uploadcare::Configuration]
62
+ # @param request_options [Hash]
63
+ # @return [Uploadcare::Resources::DocumentConversion]
64
+ def self.info_for(uuid:, client: nil, config: Uploadcare.configuration, request_options: {})
65
+ resolved_client = resolve_client(client: client, config: config)
66
+ new({ 'uuid' => uuid }, resolved_client).info(request_options: request_options)
67
+ end
68
+
69
+ # Get conversion job status.
70
+ #
71
+ # @param token [String] Job token
72
+ # @param request_options [Hash] Request options
73
+ # @return [self]
74
+ def fetch_status(token:, request_options: {})
75
+ response = Uploadcare::Result.unwrap(
76
+ client.api.rest.document_conversions.status(token: token, request_options: request_options)
77
+ )
78
+ assign_attributes(response)
79
+ self
80
+ end
81
+ end
@@ -0,0 +1,366 @@
1
+ # frozen_string_literal: true
2
+
3
+ # File resource representing an uploaded file in Uploadcare.
4
+ #
5
+ # Provides both class methods (find, list, upload, batch operations, copy)
6
+ # and instance methods (store, delete, reload, convert) for working with files.
7
+ #
8
+ # @example Finding a file
9
+ # client = Uploadcare.client
10
+ # file = client.files.find(uuid: "file-uuid")
11
+ # file.original_filename # => "photo.jpg"
12
+ #
13
+ # @example Uploading
14
+ # client = Uploadcare.client
15
+ # file = client.files.upload(::File.open("photo.jpg"), store: true)
16
+ #
17
+ # @see https://uploadcare.com/api-refs/rest-api/v0.7.0/#tag/File
18
+ class Uploadcare::Resources::File < Uploadcare::Resources::BaseResource
19
+ # API fields assigned onto file resources.
20
+ ATTRIBUTES = %i[
21
+ datetime_removed datetime_stored datetime_uploaded is_image is_ready mime_type original_file_url
22
+ original_filename size url uuid variations content_info metadata appdata source
23
+ ].freeze
24
+
25
+ attr_writer :uuid
26
+ attr_accessor :datetime_removed, :datetime_stored, :datetime_uploaded, :is_image, :is_ready, :mime_type,
27
+ :original_file_url, :original_filename, :size, :url, :variations, :content_info,
28
+ :metadata, :appdata, :source
29
+
30
+ # --- Class methods ---
31
+
32
+ # Find a file by UUID.
33
+ #
34
+ # @param uuid [String] File UUID
35
+ # @param params [Hash] Optional parameters (e.g., include: "appdata")
36
+ # @param client [Uploadcare::Client, nil] Client instance
37
+ # @param config [Uploadcare::Configuration] Configuration fallback
38
+ # @param request_options [Hash] Request options
39
+ # @return [Uploadcare::Resources::File]
40
+ def self.find(uuid:, params: {}, client: nil, config: Uploadcare.configuration, request_options: {})
41
+ resolved_client = resolve_client(client: client, config: config)
42
+ response = Uploadcare::Result.unwrap(
43
+ resolved_client.api.rest.files.info(uuid: uuid, params: params, request_options: request_options)
44
+ )
45
+ new(response, resolved_client)
46
+ end
47
+
48
+ class << self
49
+ alias retrieve find
50
+ alias info find
51
+ end
52
+
53
+ # List files with optional filtering and pagination.
54
+ #
55
+ # @param options [Hash] Query parameters (limit, ordering, etc.)
56
+ # @param client [Uploadcare::Client, nil] Client instance
57
+ # @param config [Uploadcare::Configuration] Configuration fallback
58
+ # @param request_options [Hash] Request options
59
+ # @return [Uploadcare::Collections::Paginated]
60
+ def self.list(options: {}, client: nil, config: Uploadcare.configuration, request_options: {})
61
+ resolved_client = resolve_client(client: client, config: config)
62
+ response = Uploadcare::Result.unwrap(
63
+ resolved_client.api.rest.files.list(params: options, request_options: request_options)
64
+ )
65
+
66
+ files = response['results'].map { |data| new(data, resolved_client) }
67
+
68
+ Uploadcare::Collections::Paginated.new(
69
+ resources: files,
70
+ next_page: response['next'],
71
+ previous_page: response['previous'],
72
+ per_page: response['per_page'],
73
+ total: response['total'],
74
+ api_client: resolved_client.api.rest.files,
75
+ resource_class: self,
76
+ client: resolved_client,
77
+ request_options: request_options
78
+ )
79
+ end
80
+
81
+ # Upload a single file.
82
+ #
83
+ # @param file [File, IO] File to upload
84
+ # @param client [Uploadcare::Client, nil] Client instance
85
+ # @param config [Uploadcare::Configuration] Configuration fallback
86
+ # @param options [Hash] Upload options
87
+ # @return [Uploadcare::Resources::File]
88
+ def self.upload(file, client: nil, config: Uploadcare.configuration, request_options: {}, **options)
89
+ resolved_client = resolve_client(client: client, config: config)
90
+ resolved_client.uploads.upload_file(file: file, request_options: request_options, **options)
91
+ end
92
+
93
+ # Upload multiple files.
94
+ #
95
+ # @param files [Array<File, IO>] Files to upload
96
+ # @param client [Uploadcare::Client, nil] Client instance
97
+ # @param config [Uploadcare::Configuration] Configuration fallback
98
+ # @param options [Hash] Upload options
99
+ # @return [Array<Uploadcare::Resources::File>]
100
+ def self.upload_many(files, client: nil, config: Uploadcare.configuration, request_options: {}, **options)
101
+ resolved_client = resolve_client(client: client, config: config)
102
+ resolved_client.uploads.upload_files(files: files, request_options: request_options, **options)
103
+ end
104
+
105
+ # Upload a file from URL.
106
+ #
107
+ # @param url [String] Source URL
108
+ # @param client [Uploadcare::Client, nil] Client instance
109
+ # @param config [Uploadcare::Configuration] Configuration fallback
110
+ # @param options [Hash] Upload options
111
+ # @return [Uploadcare::Resources::File]
112
+ def self.upload_url(url, client: nil, config: Uploadcare.configuration, request_options: {}, **options)
113
+ resolved_client = resolve_client(client: client, config: config)
114
+ resolved_client.uploads.upload_from_url(url: url, request_options: request_options, **options)
115
+ end
116
+
117
+ class << self
118
+ alias upload_from_url upload_url
119
+ end
120
+
121
+ # Batch store files.
122
+ #
123
+ # @param uuids [Array<String>] File UUIDs to store
124
+ # @param client [Uploadcare::Client, nil] Client instance
125
+ # @param config [Uploadcare::Configuration] Configuration fallback
126
+ # @param request_options [Hash] Request options
127
+ # @return [Uploadcare::Collections::BatchResult]
128
+ def self.batch_store(uuids:, client: nil, config: Uploadcare.configuration, request_options: {})
129
+ resolved_client = resolve_client(client: client, config: config)
130
+ response = Uploadcare::Result.unwrap(
131
+ resolved_client.api.rest.files.batch_store(uuids: uuids, request_options: request_options)
132
+ )
133
+ normalized = response.transform_keys(&:to_s)
134
+
135
+ Uploadcare::Collections::BatchResult.new(
136
+ status: normalized['status'],
137
+ result: normalized['result'],
138
+ problems: normalized['problems'] || {},
139
+ client: resolved_client
140
+ )
141
+ end
142
+
143
+ # Batch delete files.
144
+ #
145
+ # @param uuids [Array<String>] File UUIDs to delete
146
+ # @param client [Uploadcare::Client, nil] Client instance
147
+ # @param config [Uploadcare::Configuration] Configuration fallback
148
+ # @param request_options [Hash] Request options
149
+ # @return [Uploadcare::Collections::BatchResult]
150
+ def self.batch_delete(uuids:, client: nil, config: Uploadcare.configuration, request_options: {})
151
+ resolved_client = resolve_client(client: client, config: config)
152
+ response = Uploadcare::Result.unwrap(
153
+ resolved_client.api.rest.files.batch_delete(uuids: uuids, request_options: request_options)
154
+ )
155
+ normalized = response.transform_keys(&:to_s)
156
+
157
+ Uploadcare::Collections::BatchResult.new(
158
+ status: normalized['status'],
159
+ result: normalized['result'],
160
+ problems: normalized['problems'] || {},
161
+ client: resolved_client
162
+ )
163
+ end
164
+
165
+ # Copy a file to local storage (class method).
166
+ #
167
+ # @param source [String] CDN URL or UUID
168
+ # @param options [Hash] Optional parameters
169
+ # @return [Uploadcare::Resources::File]
170
+ def self.local_copy(source:, options: {}, client: nil, config: Uploadcare.configuration, request_options: {})
171
+ resolved_client = resolve_client(client: client, config: config)
172
+ response = Uploadcare::Result.unwrap(
173
+ resolved_client.api.rest.files.local_copy(source: source, options: options, request_options: request_options)
174
+ )
175
+ new(response['result'], resolved_client)
176
+ end
177
+
178
+ class << self
179
+ alias copy_to_local local_copy
180
+ end
181
+
182
+ # Copy a file to remote storage (class method).
183
+ #
184
+ # @param source [String] CDN URL or UUID
185
+ # @param target [String] Custom storage name
186
+ # @param options [Hash] Optional parameters
187
+ # @return [String] URL of the copied file
188
+ def self.remote_copy(source:, target:, options: {}, client: nil, config: Uploadcare.configuration,
189
+ request_options: {})
190
+ resolved_client = resolve_client(client: client, config: config)
191
+ response = Uploadcare::Result.unwrap(
192
+ resolved_client.api.rest.files.remote_copy(
193
+ source: source, target: target, options: options, request_options: request_options
194
+ )
195
+ )
196
+ response['result']
197
+ end
198
+
199
+ class << self
200
+ alias copy_to_remote remote_copy
201
+ end
202
+
203
+ # --- Instance methods ---
204
+
205
+ # Store this file, making it permanently available.
206
+ #
207
+ # @param request_options [Hash] Request options
208
+ # @return [self]
209
+ def store(request_options: {})
210
+ response = Uploadcare::Result.unwrap(client.api.rest.files.store(uuid: uuid, request_options: request_options))
211
+ assign_attributes(response)
212
+ self
213
+ end
214
+
215
+ # Delete this file.
216
+ #
217
+ # @param request_options [Hash] Request options
218
+ # @return [self]
219
+ def delete(request_options: {})
220
+ response = Uploadcare::Result.unwrap(client.api.rest.files.delete(uuid: uuid, request_options: request_options))
221
+ assign_attributes(response)
222
+ self
223
+ end
224
+
225
+ # Reload file information from the API.
226
+ #
227
+ # @param params [Hash] Optional parameters
228
+ # @param request_options [Hash] Request options
229
+ # @return [self]
230
+ def reload(params: {}, request_options: {})
231
+ response = Uploadcare::Result.unwrap(
232
+ client.api.rest.files.info(uuid: uuid, params: params, request_options: request_options)
233
+ )
234
+ assign_attributes(response)
235
+ self
236
+ end
237
+ alias load reload
238
+
239
+ # Copy this file to local storage.
240
+ #
241
+ # @param options [Hash] Optional parameters
242
+ # @param request_options [Hash] Request options
243
+ # @return [Uploadcare::Resources::File] The copied file
244
+ def copy_to_local(options: {}, request_options: {})
245
+ response = Uploadcare::Result.unwrap(
246
+ client.api.rest.files.local_copy(source: uuid, options: options, request_options: request_options)
247
+ )
248
+ self.class.new(response['result'], client)
249
+ end
250
+ alias local_copy copy_to_local
251
+
252
+ # Copy this file to remote storage.
253
+ #
254
+ # @param target [String] Custom storage name
255
+ # @param options [Hash] Optional parameters
256
+ # @param request_options [Hash] Request options
257
+ # @return [String] URL of the copied file
258
+ def copy_to_remote(target:, options: {}, request_options: {})
259
+ response = Uploadcare::Result.unwrap(
260
+ client.api.rest.files.remote_copy(
261
+ source: uuid, target: target, options: options, request_options: request_options
262
+ )
263
+ )
264
+ response['result']
265
+ end
266
+ alias remote_copy copy_to_remote
267
+
268
+ # Convert this file to a document format.
269
+ #
270
+ # @param params [Hash] Conversion parameters (:format, etc.)
271
+ # @param options [Hash] Optional parameters (:store, etc.)
272
+ # @param request_options [Hash] Request options
273
+ # @return [Uploadcare::Resources::File] The converted file
274
+ def convert_to_document(params: {}, options: {}, request_options: {})
275
+ convert_file(params, Uploadcare::Resources::DocumentConversion, options, request_options: request_options)
276
+ end
277
+
278
+ # Convert this file to a video format.
279
+ #
280
+ # @param params [Hash] Conversion parameters (:format, :quality, etc.)
281
+ # @param options [Hash] Optional parameters (:store, etc.)
282
+ # @param request_options [Hash] Request options
283
+ # @return [Uploadcare::Resources::File] The converted file
284
+ def convert_to_video(params: {}, options: {}, request_options: {})
285
+ convert_file(params, Uploadcare::Resources::VideoConversion, options, request_options: request_options)
286
+ end
287
+
288
+ # Returns the file UUID, extracting from URL if needed.
289
+ #
290
+ # @return [String, nil]
291
+ def uuid
292
+ return @uuid if @uuid
293
+
294
+ source =
295
+ if @url
296
+ @url
297
+ elsif uploadcare_cdn_url?(@original_file_url)
298
+ @original_file_url
299
+ end
300
+ return @uuid unless source
301
+
302
+ @uuid = source[/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/]
303
+ end
304
+
305
+ # Returns the CDN URL for this file.
306
+ #
307
+ # @return [String]
308
+ def cdn_url
309
+ return @url if uploadcare_cdn_url?(@url)
310
+ return @original_file_url if uploadcare_cdn_url?(@original_file_url)
311
+ return nil unless uuid
312
+
313
+ "#{config.cdn_base}#{uuid}/"
314
+ end
315
+
316
+ private
317
+
318
+ def uploadcare_cdn_url?(value)
319
+ value.to_s.start_with?(config.cdn_base.to_s)
320
+ end
321
+
322
+ def convert_file(params, converter, options = {}, request_options: {})
323
+ raise ArgumentError, 'The first argument must be a Hash' unless params.is_a?(Hash)
324
+
325
+ params_with_symbolized_keys = params.transform_keys(&:to_sym)
326
+ params_with_symbolized_keys[:uuid] = uuid
327
+
328
+ result = if converter.respond_to?(:convert_document)
329
+ converter.convert_document(
330
+ params: params_with_symbolized_keys, options: options, config: config,
331
+ request_options: request_options
332
+ )
333
+ elsif converter.respond_to?(:convert)
334
+ converter.convert(
335
+ params: params_with_symbolized_keys, options: options, config: config,
336
+ request_options: request_options
337
+ )
338
+ else
339
+ raise Uploadcare::Exception::ConversionError,
340
+ "Converter #{converter.name} must implement .convert_document or .convert"
341
+ end
342
+
343
+ process_convert_result(result, request_options: request_options)
344
+ end
345
+
346
+ def process_convert_result(result, request_options: {})
347
+ if result.is_a?(Hash) && result['result']&.first
348
+ return process_hash_result(result, request_options: request_options)
349
+ end
350
+
351
+ if result.respond_to?(:result) && result.result.is_a?(Array) && result.result.first.is_a?(Hash)
352
+ return process_hash_result({ 'result' => result.result }, request_options: request_options)
353
+ end
354
+
355
+ result
356
+ end
357
+
358
+ def process_hash_result(result, request_options: {})
359
+ result_data = result['result'].first
360
+ if result_data['uuid']
361
+ return self.class.find(uuid: result_data['uuid'], client: client, request_options: request_options)
362
+ end
363
+
364
+ result
365
+ end
366
+ end
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ # File metadata resource for managing key-value metadata on files.
4
+ #
5
+ # @see https://uploadcare.com/api-refs/rest-api/v0.7.0/#tag/File-metadata
6
+ class Uploadcare::Resources::FileMetadata < Uploadcare::Resources::BaseResource
7
+ attr_accessor :uuid
8
+
9
+ def initialize(attributes = {}, client_or_config = nil)
10
+ super
11
+ @metadata = {}
12
+ end
13
+
14
+ # --- Instance methods ---
15
+
16
+ # Retrieve all metadata for the file.
17
+ #
18
+ # @param uuid [String, nil] File UUID (defaults to instance UUID)
19
+ # @param request_options [Hash] Request options
20
+ # @return [self]
21
+ def index(uuid: nil, request_options: {})
22
+ response = Uploadcare::Result.unwrap(
23
+ client.api.rest.file_metadata.index(uuid: uuid || @uuid, request_options: request_options)
24
+ )
25
+ @metadata = response.is_a?(Hash) ? response.transform_keys(&:to_s) : {}
26
+ self
27
+ end
28
+
29
+ # Access a metadata value by key.
30
+ #
31
+ # @param key [String, Symbol] Metadata key
32
+ # @return [String, nil] Metadata value
33
+ def [](key)
34
+ @metadata[key.to_s]
35
+ end
36
+
37
+ # Set a metadata value by key (local only, call #update to persist).
38
+ #
39
+ # @param key [String, Symbol] Metadata key
40
+ # @param value [String] Metadata value
41
+ def []=(key, value)
42
+ @metadata[key.to_s] = value
43
+ end
44
+
45
+ # Return all metadata as a hash.
46
+ #
47
+ # @return [Hash]
48
+ def to_h
49
+ @metadata.dup
50
+ end
51
+
52
+ # Update a metadata key's value on the server.
53
+ #
54
+ # @param key [String] Metadata key
55
+ # @param value [String] Metadata value
56
+ # @param uuid [String, nil] File UUID (defaults to instance UUID)
57
+ # @param request_options [Hash] Request options
58
+ # @return [String] The updated value
59
+ def update(key:, value:, uuid: nil, request_options: {})
60
+ target_uuid = uuid || @uuid
61
+ result = Uploadcare::Result.unwrap(
62
+ client.api.rest.file_metadata.update(
63
+ uuid: target_uuid, key: key, value: value, request_options: request_options
64
+ )
65
+ )
66
+ @metadata[key.to_s] = result if target_uuid == @uuid
67
+ result
68
+ end
69
+
70
+ # Retrieve a single metadata key's value.
71
+ #
72
+ # @param key [String] Metadata key
73
+ # @param uuid [String, nil] File UUID (defaults to instance UUID)
74
+ # @param request_options [Hash] Request options
75
+ # @return [String] Metadata value
76
+ def show(key:, uuid: nil, request_options: {})
77
+ target_uuid = uuid || @uuid
78
+ result = Uploadcare::Result.unwrap(
79
+ client.api.rest.file_metadata.show(uuid: target_uuid, key: key, request_options: request_options)
80
+ )
81
+ @metadata[key.to_s] = result if target_uuid == @uuid
82
+ result
83
+ end
84
+
85
+ # Delete a metadata key.
86
+ #
87
+ # @param key [String] Metadata key
88
+ # @param uuid [String, nil] File UUID (defaults to instance UUID)
89
+ # @param request_options [Hash] Request options
90
+ # @return [nil]
91
+ def delete(key:, uuid: nil, request_options: {})
92
+ target_uuid = uuid || @uuid
93
+ result = Uploadcare::Result.unwrap(
94
+ client.api.rest.file_metadata.delete(uuid: target_uuid, key: key, request_options: request_options)
95
+ )
96
+ @metadata.delete(key.to_s) if target_uuid == @uuid
97
+ result
98
+ end
99
+
100
+ # --- Class methods ---
101
+
102
+ # Get all metadata for a file.
103
+ def self.index(uuid:, client: nil, config: Uploadcare.configuration, request_options: {})
104
+ resolved_client = resolve_client(client: client, config: config)
105
+ Uploadcare::Result.unwrap(
106
+ resolved_client.api.rest.file_metadata.index(uuid: uuid, request_options: request_options)
107
+ )
108
+ end
109
+
110
+ # Get a single metadata key's value.
111
+ def self.show(uuid:, key:, client: nil, config: Uploadcare.configuration, request_options: {})
112
+ resolved_client = resolve_client(client: client, config: config)
113
+ Uploadcare::Result.unwrap(
114
+ resolved_client.api.rest.file_metadata.show(uuid: uuid, key: key, request_options: request_options)
115
+ )
116
+ end
117
+
118
+ # Update a metadata key's value.
119
+ def self.update(uuid:, key:, value:, client: nil, config: Uploadcare.configuration, request_options: {})
120
+ resolved_client = resolve_client(client: client, config: config)
121
+ Uploadcare::Result.unwrap(
122
+ resolved_client.api.rest.file_metadata.update(
123
+ uuid: uuid, key: key, value: value, request_options: request_options
124
+ )
125
+ )
126
+ end
127
+
128
+ # Delete a metadata key.
129
+ def self.delete(uuid:, key:, client: nil, config: Uploadcare.configuration, request_options: {})
130
+ resolved_client = resolve_client(client: client, config: config)
131
+ Uploadcare::Result.unwrap(
132
+ resolved_client.api.rest.file_metadata.delete(uuid: uuid, key: key, request_options: request_options)
133
+ )
134
+ end
135
+ end