shrine-uploadcare 0.3.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 66200985dae4d285580e9820867b1433fd9212573bf840b7afe0937ffda15809
4
- data.tar.gz: cd080f6783e48d1daee215bd0b2cba70f9d9d3e9355fa9643907ab0745b74a12
3
+ metadata.gz: 826464c7fa00009924eb9b89da88c3fb66fcc9e1626b27c70a473f91ca4ca41e
4
+ data.tar.gz: 1ded6035d05ba1747284362a15e4f9066d327f40072b00168b472bb530293f16
5
5
  SHA512:
6
- metadata.gz: 72048ded05537ca65af704be57c10b99833d91a2d5296a345d91bc0db82f908d6cb4f80dacce571ee56e39e2e37fbf823842b393baf2451614dba2c80642ae62
7
- data.tar.gz: 2c9017d63e9f86ab45029fb7b64ecd22319803c379c66bb9d2de81e911290a9828a63d9b2faa08cf7082d5012a453faab5db750f9794abc1156bf3a2f17e8dda
6
+ metadata.gz: 9cfa46ced7eb2d3273dc008ca3c92989df3f6a08cd9db953d5e3a8fe489f0666a036183d3007afb58e1b3a3357747ec8f385b16afa3e9cb366815ae9ba4ebde7
7
+ data.tar.gz: 161ee61ee644f3d6bf5da0259f2206623fd19762d81d5c97c9552bf876acdee720bffb4fc6592bce10c6d6253a04410754164312b89acbd48739c701cbd3fd7c
data/README.md CHANGED
@@ -8,7 +8,7 @@ with an advanced HTML widget for direct uploads.
8
8
  ## Installation
9
9
 
10
10
  ```ruby
11
- gem "shrine-uploadcare"
11
+ gem "shrine-uploadcare", "~> 1.0"
12
12
  ```
13
13
 
14
14
  ## Usage
@@ -30,14 +30,11 @@ Shrine.storages = {
30
30
 
31
31
  ### Direct uploads
32
32
 
33
- Uploadcare supports uploading files directly to the service, freeing your
34
- application from accepting file uploads. The easiest way to do that is by using
35
- Uploadcare's [HTML widget], you can see how it can be used in the
36
- shrine-uploadcare [demo app].
33
+ The `Shrine::Storage::Uploadcare` class implements the `#presign` method, so it
34
+ should work with Shrine's [presign_endpoint] plugin and Uppy's [AwsS3] plugin.
37
35
 
38
- [Secure file uploads] are also supported, you can generate signatures with
39
- `#presign` on the storage, or using the [direct_upload plugin] with `presign:
40
- true`.
36
+ If that doesn't work, you can always use Shrine's [upload_endpoint] plugin with
37
+ Uppy's [XHRUpload] plugin.
41
38
 
42
39
  ### URL operations
43
40
 
@@ -48,49 +45,20 @@ photo.image_url(resize: "200x")
48
45
  photo.image_url(crop: ["200x300", :center])
49
46
  ```
50
47
 
51
- ### Upload options
48
+ ### Metadata
52
49
 
53
- You can add upload options using the upload_options plugin or using
54
- `:upload_options` on the storage:
50
+ Uploadcare metadata is automatically stored on upload:
55
51
 
56
- ```rb
57
- Shrine::Storage::Uploadcare.new(upload_options: {...}, **uploadcare_options)
58
- ```
59
-
60
- ### Storing information
61
-
62
- You can have all Uploadcare file information saved in the uploaded file's
63
- metadata:
64
-
65
- ```rb
66
- Shrine::Storage::Uploadcare.new(store_info: true, **uploadcare_options)
67
- ```
68
52
  ```rb
69
53
  user = User.create(avatar: image_file)
70
- user.avatar.metadata["uploadcare"] #=>
54
+ user.avatar.metadata
71
55
  # {
72
- # "type" => "file",
73
- # "result" => {
74
- # "original_file_url" => "http://www.ucarecdn.com/d1d2dc43-4904-4783-bb4d-fbcf64264e63/image.png",
75
- # "image_info" => {
76
- # "height" => 45,
77
- # "width" => 91,
78
- # "geo_location" => null,
79
- # "datetime_original" => null,
80
- # "format" => "PNG"
81
- # },
82
- # "mime_type" => "image/png",
83
- # "is_ready" => true,
84
- # "url" => "https://api.uploadcare.com/files/d1d2dc43-4904-4783-bb4d-fbcf64264e63/",
85
- # "uuid" => "d1d2dc43-4904-4783-bb4d-fbcf64264e63",
86
- # "original_filename" => "image.png",
87
- # "datetime_uploaded" => "2014-09-09T16:48:57.284Z",
88
- # "size" => 12952,
89
- # "is_image" => null,
90
- # "datetime_stored" => "2014-09-09T16:48:57.291Z",
91
- # "datetime_removed" => null,
92
- # "source" => "/03ccf9ab-f266-43fb-973d-a6529c55c2ae/"
93
- # }
56
+ # "height" => 45,
57
+ # "width" => 91,
58
+ # "geo_location" => null,
59
+ # "datetime_original" => null,
60
+ # "format" => "PNG",
61
+ # ...
94
62
  # }
95
63
  ```
96
64
 
@@ -126,8 +94,8 @@ $ rake test
126
94
 
127
95
  [Uploadcare]: https://uploadcare.com/
128
96
  [Shrine]: https://github.com/shrinerb/shrine
129
- [HTML widget]: https://uploadcare.com/documentation/widget/
130
- [demo app]: /demo
131
- [Secure file uploads]: https://uploadcare.com/documentation/upload/#secure-uploads
132
- [direct_upload plugin]: http://shrinerb.com/rdoc/classes/Shrine/Plugins/DirectUpload.html
133
97
  [URL operations]: https://uploadcare.com/documentation/cdn/
98
+ [presign_endpoint]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/presign_endpoint.md#readme
99
+ [upload_endpoint]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/upload_endpoint.md#readme
100
+ [AwsS3]: https://uppy.io/docs/aws-s3/
101
+ [XHRUpload]: https://uppy.io/docs/xhr-upload/
@@ -9,159 +9,92 @@ class Shrine
9
9
  class Uploadcare
10
10
  Error = Class.new(StandardError)
11
11
 
12
- attr_reader :uploadcare
12
+ attr_reader :api
13
13
 
14
- def initialize(store_info: false, upload_options: {}, **options)
15
- @uploadcare = ::Uploadcare::Api.new(api_version: "0.5", **options)
16
- @store_info = store_info
17
- @upload_options = upload_options
14
+ def initialize(**options)
15
+ @api = ::Uploadcare::Api.new(**options)
18
16
  end
19
17
 
20
18
  def upload(io, id, shrine_metadata: {}, **upload_options)
21
- result = _upload(io, id, shrine_metadata: shrine_metadata, **upload_options)
22
- update_metadata!(shrine_metadata, result)
23
- update_id!(id, result)
19
+ file = _upload(io, id, shrine_metadata: shrine_metadata, **upload_options)
20
+ file.load_data
21
+
22
+ update_metadata!(shrine_metadata, file)
23
+ update_id!(id, file)
24
+
25
+ file
24
26
  end
25
27
 
26
28
  def open(id, **options)
27
29
  Down::Http.open(url(id), **options)
30
+ rescue Down::NotFound
31
+ raise Shrine::FileNotFound, "file #{id.inspect} not found on storage"
28
32
  end
29
33
 
30
34
  def exists?(id)
31
- response = api_client.get("/files/#{id}/")
32
- !!response.body["datetime_stored"]
35
+ file = api.file(id)
36
+ file.load_data
37
+ !!file.datetime_stored
33
38
  rescue ::Uploadcare::Error::RequestError::NotFound
34
39
  false
35
40
  end
36
41
 
37
42
  def delete(id)
38
- api_client.delete("/files/#{id}/storage/")
43
+ file = api.file(id)
44
+ file.delete
39
45
  end
40
46
 
41
47
  def url(id, **options)
42
- operations = options.to_a.map { |operation| operation.flatten.join("/") }
43
- file(id, operations).cdn_url(true)
44
- end
45
-
46
- def clear!
47
- response = api_client.get("/files/", stored: true, limit: 1000)
48
- loop do
49
- uuids = response.body["results"].map { |result| result.fetch("uuid") }
50
- batch_delete(uuids) unless uuids.empty?
51
- return if (next_url = response.body["next"]).nil?
52
- response = api_client.get(URI(next_url).request_uri)
53
- end
48
+ file = api.file(id)
49
+ file.operations = options.map { |operation| operation.flatten.join("/") }
50
+ file.cdn_url(true)
54
51
  end
55
52
 
56
53
  def presign(id = nil, **options)
57
54
  expire = Time.now.to_i + (options[:expires_in] || 60*60)
58
- secret_key = uploadcare.options[:private_key]
55
+ secret_key = api.options[:private_key]
59
56
 
60
57
  signature = Digest::MD5.hexdigest(secret_key + expire.to_s)
61
58
 
62
59
  fields = {
63
- UPLOADCARE_PUB_KEY: uploadcare.options[:public_key],
60
+ UPLOADCARE_PUB_KEY: api.options[:public_key],
64
61
  signature: signature,
65
62
  expire: expire,
66
63
  }
67
64
 
68
- url = upload_client.url_prefix + "base/"
65
+ url = URI.join(api.options[:upload_url_base], "base/").to_s
69
66
 
70
67
  { method: :post, url: url, fields: fields }
71
68
  end
72
69
 
73
- protected
74
-
75
- def file(id, operations = [])
76
- ::Uploadcare::Api::File.new(uploadcare, id, operations: operations)
70
+ def clear!
71
+ api.file_list(limit: 1000).each_slice(100) do |file_batch|
72
+ api.delete_files(file_batch)
73
+ end
77
74
  end
78
75
 
79
76
  private
80
77
 
81
- def _upload(io, id, **options)
82
- if uploadcare_file?(io)
83
- store(io, id, **options)
84
- else
85
- create(io, id, **options)
86
- end
87
- end
88
-
89
- def store(io, id, **options)
90
- response = api_client.put "/files/#{io.id}/storage/"
91
- response.body
92
- end
78
+ def _upload(io, id, shrine_metadata: {}, **upload_options)
79
+ options = { store: true }
80
+ options.merge!(upload_options)
93
81
 
94
- def create(io, id, **options)
95
82
  if remote_file?(io)
96
- create_from_url(io, id, **options)
83
+ api.upload_from_url(io.url, options)
97
84
  else
98
- create_from_file(io, id, **options)
99
- end
100
- end
101
-
102
- def create_from_url(io, id, shrine_metadata: {}, **upload_options)
103
- options = {source_url: io.url, store: 1, pub_key: uploadcare.options[:public_key]}
104
- options.update(@upload_options).update(upload_options)
105
- response = upload_client.post "/from_url/", options
106
- token = response.body.fetch("token")
107
-
108
- loop do
109
- response = upload_client.get "/from_url/status/", token: token
110
- raise Error, response.body["error"] if response.body["status"] == "error"
111
- break response.body if response.body["status"] == "success"
112
- sleep 0.5
113
- end
114
- rescue ::Uploadcare::Error::RequestError::Forbidden => error
115
- raise Error, "You must allow \"automatic file storing\" in project settings"
116
- end
117
-
118
- def create_from_file(io, id, shrine_metadata: {}, **upload_options)
119
- options = {UPLOADCARE_PUB_KEY: uploadcare.options[:public_key], UPLOADCARE_STORE: 1}
120
- options.update(@upload_options).update(upload_options)
121
- io = Faraday::UploadIO.new(io, shrine_metadata["mime_type"], shrine_metadata["filename"])
122
- io.instance_eval { def length; size; end } # hack for multipart-post
123
- response = upload_client.post "/base/", file: io, **options
124
- {"uuid" => response.body.fetch("file")}
125
- rescue ::Uploadcare::Error::RequestError::Forbidden => error
126
- raise Error, "You must allow \"automatic file storing\" in project settings"
127
- end
128
-
129
- def batch_delete(ids)
130
- ids.each_slice(100) do |ids_slice|
131
- api_client.delete("/files/storage/") do |request|
132
- request.body = ids_slice.to_json
133
- request.headers["Content-Type"] = "application/json"
85
+ Shrine.with_file(io) do |file|
86
+ api.upload(file, options)
134
87
  end
135
88
  end
136
89
  end
137
90
 
138
- def api_client
139
- uploadcare.instance_variable_get("@api_connection")
91
+ def update_metadata!(metadata, file)
92
+ metadata.merge!(file.image_info.to_h)
93
+ metadata.merge!("mime_type" => file.mime_type, "size" => file.size)
140
94
  end
141
95
 
142
- def upload_client
143
- uploadcare.instance_variable_get("@upload_connection")
144
- end
145
-
146
- def update_metadata!(metadata, result)
147
- retrieved_metadata = {
148
- "mime_type" => result["mime_type"],
149
- "width" => result["image_info"] && result["image_info"]["width"],
150
- "height" => result["image_info"] && result["image_info"]["height"],
151
- "size" => result["size"],
152
- }
153
- retrieved_metadata.reject! { |key, value| value.nil? }
154
- retrieved_metadata["uploadcare"] = result if @store_info
155
-
156
- metadata.update(retrieved_metadata)
157
- end
158
-
159
- def update_id!(id, result)
160
- id.replace(result.fetch("uuid"))
161
- end
162
-
163
- def uploadcare_file?(io)
164
- io.is_a?(UploadedFile) && io.storage.is_a?(Storage::Uploadcare)
96
+ def update_id!(id, file)
97
+ id.replace(file.uuid)
165
98
  end
166
99
 
167
100
  def remote_file?(io)
@@ -170,3 +103,15 @@ class Shrine
170
103
  end
171
104
  end
172
105
  end
106
+
107
+ module Uploadcare
108
+ module UploadingApi
109
+ class UploadParams
110
+ # fix determining MIME type
111
+ def extract_mime_type(file)
112
+ mime_type = MIME::Types.of(file.path).first
113
+ mime_type.content_type if mime_type
114
+ end
115
+ end
116
+ end
117
+ end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = "shrine-uploadcare"
3
- gem.version = "0.3.1"
3
+ gem.version = "1.0.0"
4
4
 
5
5
  gem.required_ruby_version = ">= 2.1"
6
6
 
@@ -13,9 +13,9 @@ Gem::Specification.new do |gem|
13
13
  gem.files = Dir["README.md", "LICENSE.txt", "lib/**/*.rb", "*.gemspec"]
14
14
  gem.require_path = "lib"
15
15
 
16
- gem.add_dependency "shrine", ">= 2.11", "< 4"
17
- gem.add_dependency "uploadcare-ruby", "~> 1.0.5"
18
- gem.add_dependency "down", "~> 4.4"
16
+ gem.add_dependency "shrine", ">= 3.0.0.rc", "< 4"
17
+ gem.add_dependency "uploadcare-ruby", "~> 2.1"
18
+ gem.add_dependency "down", "~> 5.0"
19
19
  gem.add_dependency "http", ">= 3.2", "< 5"
20
20
 
21
21
  gem.add_development_dependency "rake"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shrine-uploadcare
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janko Marohnić
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-25 00:00:00.000000000 Z
11
+ date: 2019-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: shrine
@@ -16,7 +16,7 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '2.11'
19
+ version: 3.0.0.rc
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
22
  version: '4'
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '2.11'
29
+ version: 3.0.0.rc
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '4'
@@ -36,28 +36,28 @@ dependencies:
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: 1.0.5
39
+ version: '2.1'
40
40
  type: :runtime
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: 1.0.5
46
+ version: '2.1'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: down
49
49
  requirement: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '4.4'
53
+ version: '5.0'
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '4.4'
60
+ version: '5.0'
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: http
63
63
  requirement: !ruby/object:Gem::Requirement