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 +4 -4
- data/README.md +18 -50
- data/lib/shrine/storage/uploadcare.rb +50 -105
- data/shrine-uploadcare.gemspec +4 -4
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 826464c7fa00009924eb9b89da88c3fb66fcc9e1626b27c70a473f91ca4ca41e
|
4
|
+
data.tar.gz: 1ded6035d05ba1747284362a15e4f9066d327f40072b00168b472bb530293f16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
34
|
-
|
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
|
-
|
39
|
-
|
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
|
-
###
|
48
|
+
### Metadata
|
52
49
|
|
53
|
-
|
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
|
54
|
+
user.avatar.metadata
|
71
55
|
# {
|
72
|
-
# "
|
73
|
-
# "
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
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 :
|
12
|
+
attr_reader :api
|
13
13
|
|
14
|
-
def initialize(
|
15
|
-
@
|
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
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
32
|
-
|
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
|
-
|
43
|
+
file = api.file(id)
|
44
|
+
file.delete
|
39
45
|
end
|
40
46
|
|
41
47
|
def url(id, **options)
|
42
|
-
|
43
|
-
file
|
44
|
-
|
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 =
|
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:
|
60
|
+
UPLOADCARE_PUB_KEY: api.options[:public_key],
|
64
61
|
signature: signature,
|
65
62
|
expire: expire,
|
66
63
|
}
|
67
64
|
|
68
|
-
url =
|
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
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
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, **
|
82
|
-
|
83
|
-
|
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
|
-
|
83
|
+
api.upload_from_url(io.url, options)
|
97
84
|
else
|
98
|
-
|
99
|
-
|
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
|
139
|
-
|
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
|
143
|
-
|
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
|
data/shrine-uploadcare.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |gem|
|
2
2
|
gem.name = "shrine-uploadcare"
|
3
|
-
gem.version = "0.
|
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", ">=
|
17
|
-
gem.add_dependency "uploadcare-ruby", "~> 1
|
18
|
-
gem.add_dependency "down", "~>
|
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.
|
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-
|
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:
|
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:
|
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
|
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
|
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: '
|
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: '
|
60
|
+
version: '5.0'
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: http
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|