activestorage-imgur 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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +90 -0
- data/Rakefile +6 -0
- data/app/controllers/active_storage/imgur_controller.rb +19 -0
- data/app/models/active_storage/imgur_key_mapping.rb +6 -0
- data/config/routes.rb +3 -0
- data/lib/active_storage/imgur/engine.rb +27 -0
- data/lib/active_storage/imgur/model_extension.rb +35 -0
- data/lib/active_storage/imgur/service.rb +193 -0
- data/lib/active_storage/imgur/validator.rb +17 -0
- data/lib/active_storage/imgur/version.rb +5 -0
- data/lib/active_storage/service/imgur_service.rb +3 -0
- data/lib/activestorage-imgur.rb +10 -0
- data/lib/generators/active_storage_imgur/install_generator.rb +17 -0
- data/lib/generators/active_storage_imgur/templates/create_active_storage_imgur_key_mappings.rb +9 -0
- metadata +171 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 388008cb63e4720d852bad54c1083ba4b096084a265942643e85ad1a03ec39ff
|
4
|
+
data.tar.gz: fc07d05be417ea7744ead43ffe2608dfde9026b2a78564836f718cf007c306a1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 391a41de76e910ea621ca9bdb47608205684c4788bc4aa6e40d635a4b80942b5dcd3782c4a44d5c00076f92875f0cbc00dce281fe966041f68acfe0bd2d122bb
|
7
|
+
data.tar.gz: 0bc9e954b2fb8dd534938b9b2307421743e100818091c0df1e70ad61e15703b3f0a4883a54940a9a31181c34809f8998e6e886b145e48420e8ea02f5e418b031
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2018 Yi Feng
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# ActiveStorage::Imgur
|
2
|
+
|
3
|
+
An ActiveStorage driver for storing `images` on [Imgur hosting](https://imgur.com/).
|
4
|
+
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'activestorage-imgur'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
```bash
|
15
|
+
$ bundle
|
16
|
+
```
|
17
|
+
|
18
|
+
## Quick Start
|
19
|
+
|
20
|
+
1. generate a migration that creates the dependent table:
|
21
|
+
```
|
22
|
+
# if you never use activestorage, run rails active_storage:install first.
|
23
|
+
|
24
|
+
rails g active_storage_imgur:install
|
25
|
+
rails db:migrate
|
26
|
+
```
|
27
|
+
2. Set `config.active_storage.service` to `:imgur` in any of `config/environments/*.rb` files.
|
28
|
+
3. Set the imgur config in your `config/storage.yml`:
|
29
|
+
```
|
30
|
+
imgur:
|
31
|
+
service: Imgur
|
32
|
+
client_id: <%= ENV['IMGUR_CLIENT_ID'] %>
|
33
|
+
client_secret: <%= ENV['IMGUR_CLIENT_SECRET'] %>
|
34
|
+
access_token: <%= ENV['IMGUR_ACCESS_TOKEN'] %>
|
35
|
+
refresh_token: <%= ENV['IMGUR_REFRESH_TOKEN'] %>
|
36
|
+
```
|
37
|
+
|
38
|
+
for environment variables on the above, follow steps:
|
39
|
+
|
40
|
+
1. sign an imgur account: [https://imgur.com/](https://imgur.com/)
|
41
|
+
2. to create an imgur application visit: [https://api.imgur.com/oauth2/addclient](https://api.imgur.com/oauth2/addclient)
|
42
|
+
3. you will get client_id and client_secret after creating an application.
|
43
|
+
4. run `rails imgur:authorize CLIENT_ID='CLIENT_ID' CLIENT_SECRET='CLIENT_SECRET'` to get `access_token` and `refresh_token`.
|
44
|
+
|
45
|
+
3. Add attachment to your model just like explanation of [activestorage](http://edgeguides.rubyonrails.org/active_storage_overview.html):
|
46
|
+
|
47
|
+
```
|
48
|
+
class User
|
49
|
+
has_one_attached :avatar
|
50
|
+
has_many_attached :photos
|
51
|
+
...
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
```
|
56
|
+
<%= form_for @user do |form| %>
|
57
|
+
<% if @user.errors.any? %>
|
58
|
+
<ul>
|
59
|
+
<% @user.errors.full_messages.each do |msg| %>
|
60
|
+
<li><%= msg %></li>
|
61
|
+
<% end %>
|
62
|
+
</ul>
|
63
|
+
<% end %>
|
64
|
+
|
65
|
+
Avatar: <%= form.file_field :avatar %>
|
66
|
+
Photo: <%= form.file_field :photos, multiple: true %>
|
67
|
+
<%= form.submit %>
|
68
|
+
<% end %>
|
69
|
+
```
|
70
|
+
|
71
|
+
```
|
72
|
+
<%= image_tag user.avatar %>
|
73
|
+
<%= image_tag user.photos.first.variant(resize: "100x100") %>
|
74
|
+
```
|
75
|
+
|
76
|
+
for more detail usage like uploading, image displaying. see official documentations[activestorage](http://edgeguides.rubyonrails.org/active_storage_overview.html).
|
77
|
+
|
78
|
+
|
79
|
+
## Be careful
|
80
|
+
|
81
|
+
1. this gem has built-in validation to validate image file.
|
82
|
+
attachment can be nil, if it presents, it only accept image type.
|
83
|
+
if your app only accept files with image types, it should be fine.
|
84
|
+
2. though imgur is free, it still has rate limits, if your application hit the daily limit, uploading function will probably be terminated.
|
85
|
+
|
86
|
+
## Contributing
|
87
|
+
Contribution directions go here.
|
88
|
+
|
89
|
+
## License
|
90
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
class ActiveStorage::ImgurController < ActiveStorage::DiskController
|
2
|
+
def update
|
3
|
+
if token = decode_verified_token
|
4
|
+
imgur_service.upload token[:key], request.body, checksum: token[:checksum]
|
5
|
+
head :no_content
|
6
|
+
else
|
7
|
+
head :not_found
|
8
|
+
end
|
9
|
+
rescue ActiveStorage::IntegrityError
|
10
|
+
head :unprocessable_entity
|
11
|
+
ensure
|
12
|
+
response.stream.close
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def imgur_service
|
17
|
+
ActiveStorage::Blob.service
|
18
|
+
end
|
19
|
+
end
|
data/config/routes.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'active_support/lazy_load_hooks'
|
2
|
+
|
3
|
+
module ActiveStorage
|
4
|
+
module Imgur
|
5
|
+
class Engine < ::Rails::Engine
|
6
|
+
isolate_namespace ActiveStorage::Imgur
|
7
|
+
|
8
|
+
initializer 'include imgur validator' do
|
9
|
+
ActiveStorage::Attached::One.include ActiveStorage::Imgur::Validator
|
10
|
+
ActiveStorage::Attached::Many.include ActiveStorage::Imgur::Validator
|
11
|
+
end
|
12
|
+
|
13
|
+
initializer 'include model extension' do
|
14
|
+
ActiveRecord::Base.include ActiveStorage::Imgur::ModelExtension
|
15
|
+
end
|
16
|
+
|
17
|
+
initializer 'enhance Imgur::Communication' do
|
18
|
+
::Imgurapi::Communication
|
19
|
+
end
|
20
|
+
|
21
|
+
rake_tasks do
|
22
|
+
load 'imgurapi/tasks/tasks.rake'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module ActiveStorage
|
2
|
+
module Imgur::ModelExtension
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
class_methods do
|
6
|
+
def has_one_attached(*arg)
|
7
|
+
super(*arg)
|
8
|
+
name = arg.first
|
9
|
+
validate_image(name)
|
10
|
+
end
|
11
|
+
|
12
|
+
def has_many_attached(*arg)
|
13
|
+
super(*arg)
|
14
|
+
name = arg.first
|
15
|
+
validate_image(name)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def validate_image(name)
|
20
|
+
validate "validate_imgur_#{name}".to_sym
|
21
|
+
|
22
|
+
generated_association_methods.class_eval <<-CODE
|
23
|
+
attr_accessor :invalid_#{name}
|
24
|
+
|
25
|
+
def validate_imgur_#{name}
|
26
|
+
if invalid_#{name}
|
27
|
+
errors.add(:#{name}, "is not an image")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
CODE
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,193 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'down'
|
3
|
+
|
4
|
+
module ActiveStorage
|
5
|
+
module Imgur
|
6
|
+
class Service < ActiveStorage::Service
|
7
|
+
class NotAnImage < StandardError; end
|
8
|
+
|
9
|
+
attr_reader :client
|
10
|
+
|
11
|
+
def initialize(client_id:, client_secret:, refresh_token:, access_token:)
|
12
|
+
@client = ::Imgurapi::Session.instance(
|
13
|
+
client_id: client_id, client_secret: client_secret,
|
14
|
+
refresh_token: refresh_token, access_token: access_token)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Upload the +io+ to the +key+ specified. If a +checksum+ is provided, the service will
|
18
|
+
# ensure a match when the upload has completed or raise an ActiveStorage::IntegrityError.
|
19
|
+
def upload(key, io, checksum: nil)
|
20
|
+
instrument :upload, key: key, checksum: checksum do
|
21
|
+
if io.is_a?(StringIO)
|
22
|
+
io = string_io_to_file(key, io)
|
23
|
+
end
|
24
|
+
|
25
|
+
ensure_integrity_of(key, io, checksum) if checksum
|
26
|
+
image = client.image.image_upload(io)
|
27
|
+
|
28
|
+
ActiveStorage::ImgurKeyMapping.create(key: key, imgur_id: image.id)
|
29
|
+
end
|
30
|
+
rescue StandardError => e
|
31
|
+
if e.message.match(/must be an image/)
|
32
|
+
raise NotAnImage
|
33
|
+
else
|
34
|
+
raise e
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Return the content of the file at the +key+.
|
39
|
+
def download(key, &block)
|
40
|
+
if block_given?
|
41
|
+
instrument :streaming_download, key: key do
|
42
|
+
stream(key, &block)
|
43
|
+
end
|
44
|
+
else
|
45
|
+
instrument :download, key: key do
|
46
|
+
File.binread file_for(key)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Return the partial content in the byte +range+ of the file at the +key+.
|
52
|
+
def download_chunk(key, range)
|
53
|
+
instrument :download_chunk, key: key, range: range do
|
54
|
+
file = file_for(key)
|
55
|
+
file.seek range.begin
|
56
|
+
file.read range.size
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Delete the file at the +key+.
|
61
|
+
def delete(key)
|
62
|
+
instrument :delete, key: key do
|
63
|
+
map = find_map_by_key(key)
|
64
|
+
if map
|
65
|
+
client.image.image_delete(map.imgur_id)
|
66
|
+
map.destroy!
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Delete files at keys starting with the +prefix+.
|
72
|
+
def delete_prefixed(prefix)
|
73
|
+
instrument :delete_prefixed, prefix: prefix do
|
74
|
+
maps = ActiveStorage::ImgurKeyMapping.by_prefix_key(prefix)
|
75
|
+
maps.each do |map|
|
76
|
+
client.image.image_delete(map.imgur_id)
|
77
|
+
map.destroy!
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Return +true+ if a file exists at the +key+.
|
83
|
+
def exist?(key)
|
84
|
+
instrument :exist, key: key do |payload|
|
85
|
+
id = map_key_to_id(key)
|
86
|
+
answer = id.present?
|
87
|
+
|
88
|
+
payload[:exist] = answer
|
89
|
+
answer
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Returns a signed, temporary URL for the file at the +key+. The URL will be valid for the amount
|
94
|
+
# of seconds specified in +expires_in+. You must also provide the +disposition+ (+:inline+ or +:attachment+),
|
95
|
+
# +filename+, and +content_type+ that you wish the file to be served with on request.
|
96
|
+
def url(key, expires_in:, disposition:, filename:, content_type:)
|
97
|
+
instrument :url, key: key do |payload|
|
98
|
+
image = image_for(key)
|
99
|
+
|
100
|
+
image.link.tap do |url|
|
101
|
+
payload[:url] = url
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Returns a signed, temporary URL that a direct upload file can be PUT to on the +key+.
|
107
|
+
# The URL will be valid for the amount of seconds specified in +expires_in+.
|
108
|
+
# You must also provide the +content_type+, +content_length+, and +checksum+ of the file
|
109
|
+
# that will be uploaded. All these attributes will be validated by the service upon upload.
|
110
|
+
def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:)
|
111
|
+
instrument :url, key: key do |payload|
|
112
|
+
verified_token_with_expiration = ActiveStorage.verifier.generate(
|
113
|
+
{
|
114
|
+
key: key,
|
115
|
+
content_type: content_type,
|
116
|
+
content_length: content_length,
|
117
|
+
checksum: checksum
|
118
|
+
},
|
119
|
+
{ expires_in: expires_in,
|
120
|
+
purpose: :blob_token }
|
121
|
+
)
|
122
|
+
|
123
|
+
generated_url = url_helpers.update_rails_imgur_service_url(verified_token_with_expiration, host: current_host)
|
124
|
+
|
125
|
+
payload[:url] = generated_url
|
126
|
+
generated_url
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def headers_for_direct_upload(key, content_type:, checksum:, **)
|
131
|
+
{ "Content-Type" => content_type, "Content-MD5" => checksum }
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
def ensure_integrity_of(key, file, checksum)
|
136
|
+
unless Digest::MD5.file(file).base64digest == checksum
|
137
|
+
delete key
|
138
|
+
raise ActiveStorage::IntegrityError
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def find_map_by_key(key)
|
143
|
+
ActiveStorage::ImgurKeyMapping.find_by(key: key)
|
144
|
+
end
|
145
|
+
|
146
|
+
def map_key_to_id(key)
|
147
|
+
map = find_map_by_key(key)
|
148
|
+
if map
|
149
|
+
map.imgur_id
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def image_for(key)
|
154
|
+
id = map_key_to_id(key)
|
155
|
+
client.image.image(id)
|
156
|
+
end
|
157
|
+
|
158
|
+
def file_for(key)
|
159
|
+
image = image_for(key)
|
160
|
+
Down.download(image.link)
|
161
|
+
end
|
162
|
+
|
163
|
+
def string_io_to_file(key, string_io)
|
164
|
+
ext = File.extname(key)
|
165
|
+
base = File.basename(key, ext)
|
166
|
+
Tempfile.new([base, ext]).tap do |file|
|
167
|
+
file.write string_io
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def stream(key)
|
172
|
+
image = image_for(key)
|
173
|
+
remote_file = Down.open(image.link)
|
174
|
+
|
175
|
+
chunk_size = 128.kilobytes
|
176
|
+
|
177
|
+
|
178
|
+
while !remote_file.eof?
|
179
|
+
yield remote_file.read(chunk_size)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def url_helpers
|
184
|
+
@url_helpers ||= Rails.application.routes.url_helpers
|
185
|
+
end
|
186
|
+
|
187
|
+
def current_host
|
188
|
+
ActiveStorage::Current.host
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActiveStorage
|
2
|
+
module Imgur::Validator
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
alias_method :old_attach, :attach
|
7
|
+
|
8
|
+
def attach(*attachables)
|
9
|
+
record.public_send("invalid_#{name}=", false)
|
10
|
+
old_attach(*attachables)
|
11
|
+
rescue ActiveStorage::Imgur::Service::NotAnImage
|
12
|
+
record.public_send("invalid_#{name}=", true)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActiveStorageImgur
|
2
|
+
class InstallGenerator < Rails::Generators::Base
|
3
|
+
include Rails::Generators::Migration
|
4
|
+
source_root File.expand_path('../templates', __FILE__)
|
5
|
+
desc "Add the migrations for DoubleDouble"
|
6
|
+
|
7
|
+
def self.next_migration_number(path)
|
8
|
+
next_migration_number = current_migration_number(path) + 1
|
9
|
+
ActiveRecord::Migration.next_migration_number(next_migration_number)
|
10
|
+
end
|
11
|
+
|
12
|
+
def copy_migrations
|
13
|
+
migration_template "create_active_storage_imgur_key_mappings.rb",
|
14
|
+
"db/migrate/create_active_storage_imgur_key_mappings.rb"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: activestorage-imgur
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yi Feng
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-07-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: imgurapi
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: down
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.4'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4.4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: image_processing
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.2'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.2'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sqlite3
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.3'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.3'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.11'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.11'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: dotenv-rails
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '2.5'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '2.5'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: mocha
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.5'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '1.5'
|
125
|
+
description:
|
126
|
+
email:
|
127
|
+
- yfxie@me.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- MIT-LICENSE
|
133
|
+
- README.md
|
134
|
+
- Rakefile
|
135
|
+
- app/controllers/active_storage/imgur_controller.rb
|
136
|
+
- app/models/active_storage/imgur_key_mapping.rb
|
137
|
+
- config/routes.rb
|
138
|
+
- lib/active_storage/imgur/engine.rb
|
139
|
+
- lib/active_storage/imgur/model_extension.rb
|
140
|
+
- lib/active_storage/imgur/service.rb
|
141
|
+
- lib/active_storage/imgur/validator.rb
|
142
|
+
- lib/active_storage/imgur/version.rb
|
143
|
+
- lib/active_storage/service/imgur_service.rb
|
144
|
+
- lib/activestorage-imgur.rb
|
145
|
+
- lib/generators/active_storage_imgur/install_generator.rb
|
146
|
+
- lib/generators/active_storage_imgur/templates/create_active_storage_imgur_key_mappings.rb
|
147
|
+
homepage: https://github.com/yfxie/activestorage-imgur
|
148
|
+
licenses:
|
149
|
+
- MIT
|
150
|
+
metadata: {}
|
151
|
+
post_install_message:
|
152
|
+
rdoc_options: []
|
153
|
+
require_paths:
|
154
|
+
- lib
|
155
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
161
|
+
requirements:
|
162
|
+
- - ">="
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: '0'
|
165
|
+
requirements: []
|
166
|
+
rubyforge_project:
|
167
|
+
rubygems_version: 2.7.6
|
168
|
+
signing_key:
|
169
|
+
specification_version: 4
|
170
|
+
summary: An ActiveStorage driver for storing images on Imgur hosting.
|
171
|
+
test_files: []
|