paperclip-storage-aliyun 0.0.3 → 0.1.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/.editorconfig +13 -0
- data/.rubocop.yml +11 -0
- data/Gemfile +8 -7
- data/README.md +9 -6
- data/lib/aliyun/connection.rb +47 -47
- data/lib/aliyun/data_center.rb +27 -13
- data/lib/aliyun/errors.rb +3 -3
- data/lib/paperclip/storage/aliyun.rb +33 -7
- data/paperclip-storage-aliyun.gemspec +2 -2
- data/spec/aliyun_spec.rb +13 -13
- data/spec/fixtures/schema.rb +2 -2
- data/spec/lib/paperclip/storage/aliyun_spec.rb +18 -21
- data/spec/spec_helper.rb +9 -11
- data/spec/support/post.rb +6 -6
- data/spec/support/rails.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8531e6601564efe368735f05147b68f4401c495
|
4
|
+
data.tar.gz: e2317360addbbce35acd8bf2947a532cdf11f8c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f7ce3fda9227a3937a1d04e7acce987c60028187496261c493176f87e016fcaba3083fc7a9977b28af313ac9a92b0ffef6af5ba092a052f40baaac65f7b52e6
|
7
|
+
data.tar.gz: abef51e1bbeb91ac622f74ed61f17bde84026d91eba1ebf423b11833ff770b2a4912d385ec09de6728d16f4d5d0bfafb44517696f0b43e268d4cc6cd3b10753d
|
data/.editorconfig
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# EditorConfig is awesome: http://EditorConfig.org
|
2
|
+
|
3
|
+
# top-most EditorConfig file
|
4
|
+
root = true
|
5
|
+
|
6
|
+
# Unix-style newlines with a newline ending every file
|
7
|
+
[*]
|
8
|
+
charset = utf-8
|
9
|
+
indent_style = space
|
10
|
+
indent_size = 2
|
11
|
+
end_of_line = lf
|
12
|
+
insert_final_newline = true
|
13
|
+
trim_trailing_whitespace = true
|
data/.rubocop.yml
ADDED
data/Gemfile
CHANGED
@@ -1,15 +1,16 @@
|
|
1
|
-
source '
|
2
|
-
|
3
|
-
# A database backend that translates database interactions into no-ops. Using
|
4
|
-
# NullDB enables you to test your model business logic - including after_save
|
5
|
-
# hooks - without ever touching a real database.
|
6
|
-
gem "activerecord-nulldb-adapter"
|
1
|
+
source 'https://ruby.taobao.org'
|
7
2
|
|
8
3
|
gemspec
|
9
4
|
|
10
5
|
group :test do
|
11
|
-
|
6
|
+
gem 'activerecord', '~> 4.0.0'
|
7
|
+
# A database backend that translates database interactions into no-ops. Using
|
8
|
+
# NullDB enables you to test your model business logic - including after_save
|
9
|
+
# hooks - without ever touching a real database.
|
10
|
+
gem 'activerecord-nulldb-adapter'
|
12
11
|
gem 'rspec', '~> 3.3.0'
|
12
|
+
# Use rubocop to lint our Ruby codes
|
13
|
+
gem 'rubocop', '~> 0.34.2'
|
13
14
|
gem 'pry'
|
14
15
|
gem 'pry-nav'
|
15
16
|
end
|
data/README.md
CHANGED
@@ -21,24 +21,27 @@ Paperclip::Attachment.default_options[:aliyun] = {
|
|
21
21
|
access_id: '3VL9XMho8iCushj8',
|
22
22
|
access_key: 'VAUI2q7Tc6yTh1jr3kBsEUzZ84gEa2',
|
23
23
|
bucket: 'xx-test',
|
24
|
-
|
24
|
+
data_center: 'hangzhou',
|
25
25
|
internal: false
|
26
26
|
}
|
27
27
|
```
|
28
28
|
Then, in the model which defines the attachment, specify your storage and other options, for example:
|
29
29
|
```ruby
|
30
30
|
# [rails_root]/app/models/image.rb
|
31
|
-
include Paperclip::Storage::Aliyun
|
32
|
-
|
33
31
|
class Image < ActiveRecord::Base
|
34
32
|
has_attached_file :attachment, {
|
35
33
|
storage: :aliyun,
|
36
34
|
styles: { thumbnail: "60x60#"},
|
37
35
|
path: 'public/system/:class/:attachment/:id_partition/:style/:filename',
|
38
|
-
url:
|
36
|
+
url: ':aliyun_upload_url'
|
39
37
|
}
|
40
38
|
end
|
41
39
|
```
|
42
40
|
|
43
|
-
|
44
|
-
|
41
|
+
Similar to Paperclip::Storage::S3, there are four options for the url by now:
|
42
|
+
- `:aliyun_upload_url` : the url based on the options you give
|
43
|
+
- `:aliyun_internal_url` : the internal url, no matter what `options[:aliyun][:internal]` is
|
44
|
+
- `:aliyun_external_url` : the external url, no matter what `options[:aliyun][:internal]` is
|
45
|
+
- `:aliyun_alias_url` : the alias url based on the `host_alias` you give, typically used together with CDN
|
46
|
+
|
47
|
+
Please note the values above are all strings, not symbols. You could still make your own url if only you know what you are doing.
|
data/lib/aliyun/connection.rb
CHANGED
@@ -1,15 +1,23 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
require 'openssl'
|
4
2
|
require 'digest/md5'
|
5
|
-
require
|
6
|
-
require
|
3
|
+
require 'rest-client'
|
4
|
+
require 'base64'
|
7
5
|
require 'uri'
|
8
6
|
require 'aliyun/data_center'
|
9
7
|
|
10
8
|
module Aliyun
|
11
9
|
class Connection
|
12
10
|
include DataCenter
|
11
|
+
|
12
|
+
# The upload host according to the connection configurations
|
13
|
+
attr_reader :aliyun_upload_host
|
14
|
+
# The internal host
|
15
|
+
attr_reader :aliyun_internal_host
|
16
|
+
# The external host
|
17
|
+
attr_reader :aliyun_external_host
|
18
|
+
# The alias host
|
19
|
+
attr_reader :aliyun_alias_host
|
20
|
+
|
13
21
|
# Initialize the OSS connection
|
14
22
|
#
|
15
23
|
# @param [Hash] An options to specify connection details
|
@@ -18,7 +26,7 @@ module Aliyun
|
|
18
26
|
# @option bucket [String] bucket used to access
|
19
27
|
# @option data_center [String] available data center name, e.g. 'hangzhou'
|
20
28
|
# @option internal [true, false] if the service should be accessed through internal network
|
21
|
-
# @option
|
29
|
+
# @option host_alias [String] the alias of the host, such as the CDN domain name
|
22
30
|
# @note both access_id and acces_key are related to authorization algorithm:
|
23
31
|
# https://docs.aliyun.com/#/pub/oss/api-reference/access-control&signature-header
|
24
32
|
def initialize(options = {})
|
@@ -26,18 +34,10 @@ module Aliyun
|
|
26
34
|
@aliyun_access_key = options[:access_key]
|
27
35
|
@aliyun_bucket = options[:bucket]
|
28
36
|
|
29
|
-
@
|
30
|
-
|
31
|
-
@
|
32
|
-
|
33
|
-
@aliyun_host = options[:host] || @aliyun_upload_host
|
34
|
-
end
|
35
|
-
|
36
|
-
# the file host according to the connection configurations
|
37
|
-
#
|
38
|
-
# @return [String] the host value
|
39
|
-
def fetch_file_host
|
40
|
-
@aliyun_host
|
37
|
+
@aliyun_upload_host = "#{@aliyun_bucket}.#{get_endpoint(options)}"
|
38
|
+
@aliyun_internal_host = "#{@aliyun_bucket}.#{get_endpoint(options.merge(internal: true))}"
|
39
|
+
@aliyun_external_host = "#{@aliyun_bucket}.#{get_endpoint(options.merge(internal: false))}"
|
40
|
+
@aliyun_alias_host = options[:host_alias] || @aliyun_upload_host
|
41
41
|
end
|
42
42
|
|
43
43
|
# Return the meta informations for the a file specified by the path
|
@@ -68,29 +68,30 @@ module Aliyun
|
|
68
68
|
|
69
69
|
# Upload File to Aliyun OSS
|
70
70
|
# https://docs.aliyun.com/#/pub/oss/api-reference/object&PutObject
|
71
|
-
#
|
71
|
+
#
|
72
72
|
# @param path [String] the target storing path on the oss
|
73
73
|
# @param file [File] an instance of File represents a file to be uploaded
|
74
74
|
# @param options [Hash]
|
75
75
|
# - content_type - MimeType value for the file, default is "image/jpg"
|
76
|
-
#
|
76
|
+
#
|
77
77
|
# @return [String] The downloadable url of the uploaded file
|
78
78
|
# @return [nil] if the uploading failed
|
79
|
-
def put(path, file, options={})
|
79
|
+
def put(path, file, options = {})
|
80
80
|
path = format_path(path)
|
81
81
|
bucket_path = get_bucket_path(path)
|
82
|
-
content_md5 = Digest::MD5.file(file)
|
83
|
-
content_type = options[:content_type] ||
|
82
|
+
content_md5 = Digest::MD5.file(file).base64digest
|
83
|
+
content_type = options[:content_type] || 'image/jpg'
|
84
84
|
date = gmtdate
|
85
85
|
url = path_to_url(path)
|
86
|
-
auth_sign = sign(
|
86
|
+
auth_sign = sign('PUT', bucket_path, content_md5, content_type, date)
|
87
87
|
headers = {
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
88
|
+
'Authorization' => auth_sign,
|
89
|
+
'Content-Md5' => content_md5,
|
90
|
+
'Content-Type' => content_type,
|
91
|
+
'Content-Length' => file.size,
|
92
|
+
'Date' => date,
|
93
|
+
'Host' => @aliyun_upload_host,
|
94
|
+
'Expect' => '100-Continue'
|
94
95
|
}
|
95
96
|
response = RestClient.put(URI.encode(url), file, headers)
|
96
97
|
response.code == 200 ? path_to_url(path) : nil
|
@@ -107,9 +108,9 @@ module Aliyun
|
|
107
108
|
bucket_path = get_bucket_path(path)
|
108
109
|
date = gmtdate
|
109
110
|
headers = {
|
110
|
-
|
111
|
-
|
112
|
-
|
111
|
+
'Host' => @aliyun_upload_host,
|
112
|
+
'Date' => date,
|
113
|
+
'Authorization' => sign('DELETE', bucket_path, '', '', date)
|
113
114
|
}
|
114
115
|
url = path_to_url(path)
|
115
116
|
response = RestClient.delete(URI.encode(url), headers)
|
@@ -126,9 +127,9 @@ module Aliyun
|
|
126
127
|
bucket_path = get_bucket_path(path)
|
127
128
|
date = gmtdate
|
128
129
|
headers = {
|
129
|
-
|
130
|
-
|
131
|
-
|
130
|
+
'Host' => @aliyun_upload_host,
|
131
|
+
'Date' => date,
|
132
|
+
'Authorization' => sign('GET', bucket_path, '', '', date)
|
132
133
|
}
|
133
134
|
url = path_to_url(path)
|
134
135
|
response = RestClient.get(URI.encode(url), headers)
|
@@ -150,7 +151,7 @@ module Aliyun
|
|
150
151
|
#
|
151
152
|
# @return [String] a string represents the formated time, e.g. "Wed, 05 Sep. 2012 23:00:00 GMT"
|
152
153
|
def gmtdate
|
153
|
-
Time.now.gmtime.strftime(
|
154
|
+
Time.now.gmtime.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
154
155
|
end
|
155
156
|
|
156
157
|
# remove leading slashes in the path
|
@@ -158,10 +159,7 @@ module Aliyun
|
|
158
159
|
# @param path [String] the path to retrieve the file on remote storage
|
159
160
|
# @return [String] the new string after removing leading slashed
|
160
161
|
def format_path(path)
|
161
|
-
|
162
|
-
path.gsub!(/^\/+/,"")
|
163
|
-
|
164
|
-
path
|
162
|
+
path.blank? ? '' : path.gsub(%r{^/+}, '')
|
165
163
|
end
|
166
164
|
|
167
165
|
# A path consis of the bucket name and file name
|
@@ -170,7 +168,7 @@ module Aliyun
|
|
170
168
|
# @param path [String] the path to retrieve the file on remote storage
|
171
169
|
# @return [String] the expected bucket path, e.g. "test-bucket/oss-api.pdf"
|
172
170
|
def get_bucket_path(path)
|
173
|
-
[@aliyun_bucket,path].join(
|
171
|
+
[@aliyun_bucket, path].join('/')
|
174
172
|
end
|
175
173
|
|
176
174
|
# The full path contains host name to the file
|
@@ -178,11 +176,11 @@ module Aliyun
|
|
178
176
|
# @param path [String] the path to retrieve the file on remote storage
|
179
177
|
# @return [String] the expected full path, e.g. "http://martin-test.oss-cn-hangzhou.aliyuncs.com/oss-api.pdf"
|
180
178
|
def path_to_url(path)
|
181
|
-
|
182
|
-
"http://#{fetch_file_host}/#{path}"
|
179
|
+
path =~ %r{^https?://} ? path : "http://#{aliyun_upload_host}/#{path}"
|
183
180
|
end
|
184
181
|
|
185
182
|
private
|
183
|
+
|
186
184
|
# The signature algorithm
|
187
185
|
# https://docs.aliyun.com/#/pub/oss/api-reference/access-control&signature-header
|
188
186
|
#
|
@@ -190,14 +188,16 @@ module Aliyun
|
|
190
188
|
# @param content_md5 [String] the md5 value for the content to be uploaded
|
191
189
|
# @param content_type [String] the content type of the file, e.g. "application/pdf"
|
192
190
|
# @param date [String] the GMT formatted date string
|
193
|
-
def sign(verb, path, content_md5
|
191
|
+
def sign(verb, path, content_md5, content_type, date)
|
194
192
|
canonicalized_oss_headers = ''
|
195
193
|
canonicalized_resource = "/#{path}"
|
196
|
-
string_to_sign =
|
194
|
+
string_to_sign = [
|
195
|
+
verb, content_md5, content_type, date,
|
196
|
+
canonicalized_oss_headers + canonicalized_resource
|
197
|
+
].join("\n")
|
197
198
|
digest = OpenSSL::Digest.new('sha1')
|
198
199
|
h = OpenSSL::HMAC.digest(digest, @aliyun_access_key, string_to_sign)
|
199
|
-
|
200
|
-
"OSS #{@aliyun_access_id}:#{h}"
|
200
|
+
"OSS #{@aliyun_access_id}:#{Base64.encode64(h)}"
|
201
201
|
end
|
202
202
|
end
|
203
203
|
end
|
data/lib/aliyun/data_center.rb
CHANGED
@@ -1,20 +1,34 @@
|
|
1
1
|
require 'aliyun/errors'
|
2
2
|
|
3
3
|
module Aliyun
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
module DataCenter
|
5
|
+
# https://docs.aliyun.com/#/pub/oss/product-documentation/domain-region
|
6
|
+
AVAILABLE_DATA_CENTERS = %w(
|
7
|
+
oss-cn-hangzhou
|
8
|
+
oss-cn-qingdao
|
9
|
+
oss-cn-beijing
|
10
|
+
oss-cn-hongkong
|
11
|
+
oss-cn-shenzhen
|
12
|
+
oss-cn-shanghai
|
13
|
+
oss-us-west-1
|
14
|
+
oss-ap-southeast-1
|
15
|
+
)
|
8
16
|
|
9
17
|
def get_endpoint(options)
|
10
|
-
|
11
|
-
if (AVAILABLE_CHINA_DATA_CENTERS + AVAILABLE_US_DATA_CENTERS).exclude?(data_center)
|
12
|
-
raise InvalildDataCenter, "Unsupported Data Center #{data_center} Detected"
|
13
|
-
end
|
18
|
+
data_center = find_center(options[:data_center])
|
14
19
|
|
15
|
-
|
16
|
-
|
17
|
-
|
20
|
+
unless data_center && AVAILABLE_DATA_CENTERS.include?(data_center)
|
21
|
+
fail InvalildDataCenter, "Unsupported Data Center #{options[:data_center]} Detected"
|
22
|
+
end
|
23
|
+
|
24
|
+
"#{data_center}#{options[:internal] ? '-internal' : ''}.aliyuncs.com"
|
25
|
+
end
|
26
|
+
|
27
|
+
def find_center(data_center)
|
28
|
+
return if /^(oss|cn|us|ap|oss-cn)$/.match(data_center)
|
29
|
+
|
30
|
+
regexp = Regexp.new(data_center)
|
31
|
+
AVAILABLE_DATA_CENTERS.find { |center| regexp.match(center) }
|
18
32
|
end
|
19
|
-
|
20
|
-
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/aliyun/errors.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
1
|
module Aliyun
|
2
|
-
|
3
|
-
|
4
|
-
end
|
2
|
+
class InvalildDataCenter < StandardError
|
3
|
+
end
|
4
|
+
end
|
@@ -2,12 +2,38 @@ module Paperclip
|
|
2
2
|
module Storage
|
3
3
|
module Aliyun
|
4
4
|
def self.extended(base)
|
5
|
+
base.instance_eval do
|
6
|
+
@aliyun_options = @options[:aliyun]
|
7
|
+
end
|
8
|
+
|
9
|
+
[
|
10
|
+
:aliyun_upload_url, :aliyun_internal_url,
|
11
|
+
:aliyun_external_url, :aliyun_alias_url
|
12
|
+
].each do |url_style|
|
13
|
+
Paperclip.interpolates(url_style) do |attachment, style|
|
14
|
+
attachment.send(url_style, style)
|
15
|
+
end unless Paperclip::Interpolations.respond_to? url_style
|
16
|
+
end
|
5
17
|
end
|
6
18
|
|
7
|
-
def
|
8
|
-
|
19
|
+
def aliyun_upload_url(style = default_style)
|
20
|
+
"http://#{oss_connection.aliyun_upload_host}/#{path(style).sub(%r{\A/}, '')}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def aliyun_internal_url(style = default_style)
|
24
|
+
"http://#{oss_connection.aliyun_internal_host}/#{path(style).sub(%r{\A/}, '')}"
|
25
|
+
end
|
9
26
|
|
10
|
-
|
27
|
+
def aliyun_external_url(style = default_style)
|
28
|
+
"http://#{oss_connection.aliyun_external_host}/#{path(style).sub(%r{\A/}, '')}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def aliyun_alias_url(style = default_style)
|
32
|
+
"http://#{oss_connection.aliyun_alias_host}/#{path(style).sub(%r{\A/}, '')}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def exists?(style = default_style)
|
36
|
+
path(style) ? oss_connection.exists?(path(style)) : false
|
11
37
|
end
|
12
38
|
|
13
39
|
def flush_writes #:nodoc:
|
@@ -28,7 +54,7 @@ module Paperclip
|
|
28
54
|
@queued_for_delete = []
|
29
55
|
end
|
30
56
|
|
31
|
-
def copy_to_local_file(style
|
57
|
+
def copy_to_local_file(style, local_dest_path)
|
32
58
|
log("copying #{path(style)} to local file #{local_dest_path}")
|
33
59
|
local_file = ::File.open(local_dest_path, 'wb')
|
34
60
|
remote_file_str = oss_connection.get path(style)
|
@@ -37,9 +63,9 @@ module Paperclip
|
|
37
63
|
end
|
38
64
|
|
39
65
|
def oss_connection
|
40
|
-
|
41
|
-
|
42
|
-
|
66
|
+
@oss_connection ||= ::Aliyun::Connection.new(
|
67
|
+
Paperclip::Attachment.default_options[:aliyun].merge(@aliyun_options)
|
68
|
+
)
|
43
69
|
end
|
44
70
|
end
|
45
71
|
end
|
@@ -4,9 +4,9 @@ Gem::Specification.new do |s|
|
|
4
4
|
s.require_path = 'lib'
|
5
5
|
s.summary = 'Extend a Aliyun OSS storage for paperclip'
|
6
6
|
s.description = 'Extend a Aliyun OSS storage for paperclip'
|
7
|
-
s.version = '0.0
|
7
|
+
s.version = '0.1.0'
|
8
8
|
s.files = `git ls-files`.split("\n")
|
9
|
-
s.authors = ['Martin Hong']
|
9
|
+
s.authors = ['Martin Hong', 'Aidi Stan']
|
10
10
|
s.email = 'hongzeqin@gmail.com'
|
11
11
|
s.homepage = 'https://github.com/Martin91/paperclip-storage-aliyun'
|
12
12
|
s.license = 'MIT'
|
data/spec/aliyun_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'net/http'
|
4
4
|
|
5
5
|
describe Aliyun::Connection do
|
6
6
|
before :all do
|
@@ -9,7 +9,7 @@ describe Aliyun::Connection do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
describe '#initialize' do
|
12
|
-
it
|
12
|
+
it 'raise error when use invalid data center' do
|
13
13
|
expect do
|
14
14
|
::Aliyun::Connection.new data_center: 'guangzhou'
|
15
15
|
end.to raise_error(Aliyun::InvalildDataCenter)
|
@@ -17,16 +17,16 @@ describe Aliyun::Connection do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
describe '#put' do
|
20
|
-
it
|
21
|
-
url = @connection.put @path, load_attachment(
|
20
|
+
it 'upload the attachment' do
|
21
|
+
url = @connection.put @path, load_attachment('girl.jpg')
|
22
22
|
response_code = Net::HTTP.get_response(URI.parse(url)).code
|
23
|
-
expect(response_code).to eq(
|
23
|
+
expect(response_code).to eq('200')
|
24
24
|
end
|
25
25
|
|
26
|
-
it
|
27
|
-
content_type =
|
26
|
+
it 'support setting content type' do
|
27
|
+
content_type = 'application/pdf'
|
28
28
|
path = 'pdfs/masu.pdf'
|
29
|
-
@connection.put path, load_attachment(
|
29
|
+
@connection.put path, load_attachment('masu.pdf'), content_type: content_type
|
30
30
|
file_meta = @connection.head(path)
|
31
31
|
expect(file_meta[:content_type]).to eq(content_type)
|
32
32
|
|
@@ -35,19 +35,19 @@ describe Aliyun::Connection do
|
|
35
35
|
end
|
36
36
|
|
37
37
|
describe '#delete' do
|
38
|
-
it
|
38
|
+
it 'delete the attachment' do
|
39
39
|
url = @connection.delete @path
|
40
40
|
response_code = Net::HTTP.get_response(URI.parse(url)).code
|
41
|
-
expect(response_code).to eq(
|
41
|
+
expect(response_code).to eq('404')
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
describe
|
45
|
+
describe '#exists?' do
|
46
46
|
before :all do
|
47
|
-
@connection.put @path, load_attachment(
|
47
|
+
@connection.put @path, load_attachment('girl.jpg')
|
48
48
|
end
|
49
49
|
|
50
|
-
it
|
50
|
+
it 'return true if the file has been uploaded' do
|
51
51
|
expect(@connection.exists?(@path)).to be_truthy
|
52
52
|
end
|
53
53
|
|
data/spec/fixtures/schema.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require
|
2
|
+
require 'open-uri'
|
3
3
|
require 'net/http'
|
4
4
|
require 'support/post'
|
5
5
|
|
@@ -10,25 +10,22 @@ describe Paperclip::Storage::Aliyun do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
after :all do
|
13
|
-
if @post && @post.respond_to?(:id)
|
14
|
-
@post.destroy!
|
15
|
-
end
|
16
|
-
|
13
|
+
@post.destroy! if @post && @post.respond_to?(:id)
|
17
14
|
@file.close
|
18
15
|
end
|
19
16
|
|
20
|
-
describe
|
21
|
-
it
|
17
|
+
describe '#flush_writes' do
|
18
|
+
it 'uploads the attachment to Aliyun' do
|
22
19
|
response = open(@post.attachment.url)
|
23
20
|
expect(response).to be_truthy
|
24
21
|
end
|
25
22
|
|
26
|
-
it
|
23
|
+
it 'get uploaded file from Aliyun' do
|
27
24
|
attachment = open @post.attachment.url
|
28
25
|
expect(attachment.size).to eq(@file.size)
|
29
26
|
end
|
30
27
|
|
31
|
-
it
|
28
|
+
it 'set content type according to the original file' do
|
32
29
|
attachment = load_attachment('masu.pdf')
|
33
30
|
post = Post.create attachment: attachment
|
34
31
|
headers = RestClient.head(post.attachment.url).headers
|
@@ -38,8 +35,8 @@ describe Paperclip::Storage::Aliyun do
|
|
38
35
|
end
|
39
36
|
end
|
40
37
|
|
41
|
-
describe
|
42
|
-
it
|
38
|
+
describe '#exists?' do
|
39
|
+
it 'returns true if the file exists on Aliyun' do
|
43
40
|
expect(@post.attachment).to exist
|
44
41
|
end
|
45
42
|
|
@@ -48,29 +45,29 @@ describe Paperclip::Storage::Aliyun do
|
|
48
45
|
expect(post.attachment).not_to exist
|
49
46
|
end
|
50
47
|
|
51
|
-
it
|
48
|
+
it 'not raise exception when attachment not saved' do
|
52
49
|
post = Post.create
|
53
|
-
expect{post.attachment.exists?}.not_to raise_error
|
50
|
+
expect { post.attachment.exists? }.not_to raise_error
|
54
51
|
end
|
55
52
|
end
|
56
53
|
|
57
|
-
describe
|
58
|
-
it
|
59
|
-
destination = File.join(Bundler.root,
|
54
|
+
describe '#copy_to_local_file' do
|
55
|
+
it 'copies file from Aliyun to a local file' do
|
56
|
+
destination = File.join(Bundler.root, 'tmp/photo.jpg')
|
60
57
|
@post.attachment.copy_to_local_file(:original, destination)
|
61
|
-
expect(File.
|
62
|
-
|
58
|
+
expect(File.exist?(destination)).to be_truthy
|
59
|
+
|
63
60
|
File.delete destination
|
64
61
|
end
|
65
62
|
end
|
66
63
|
|
67
|
-
describe
|
68
|
-
it
|
64
|
+
describe '#flush_deletes' do
|
65
|
+
it 'deletes the attachment from Aliyun' do
|
69
66
|
attachment_url = @post.attachment.url
|
70
67
|
@post.destroy
|
71
68
|
|
72
69
|
response_code = Net::HTTP.get_response(URI.parse(attachment_url)).code
|
73
|
-
expect(response_code).to eq(
|
70
|
+
expect(response_code).to eq('404')
|
74
71
|
end
|
75
72
|
end
|
76
73
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,28 +2,26 @@ require 'pry'
|
|
2
2
|
require 'pry-nav'
|
3
3
|
require 'paperclip-storage-aliyun'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
include Paperclip::Storage::Aliyun
|
8
|
-
def file_host
|
9
|
-
oss_connection.fetch_file_host
|
10
|
-
end
|
5
|
+
Paperclip.logger.level = ::Logger::UNKNOWN
|
6
|
+
Dir[Bundler.root.join('spec/support/**/*.rb')].each(&method(:require))
|
11
7
|
|
8
|
+
# Aliyun defaults
|
12
9
|
OSS_CONNECTION_OPTIONS = {
|
13
10
|
access_id: '3VL9XMho8iCuslj8',
|
14
11
|
access_key: 'VAUI2q7Tc6yTf1jr3kBsEUzZ84gEa2',
|
15
12
|
bucket: 'martin-test',
|
16
13
|
data_center: 'hangzhou',
|
17
14
|
internal: false
|
18
|
-
#
|
15
|
+
# host_alias: nil
|
19
16
|
}
|
20
17
|
|
21
|
-
#
|
18
|
+
# Paperclip defaults
|
22
19
|
Paperclip::Attachment.default_options[:storage] = :aliyun
|
23
|
-
Paperclip::Attachment.default_options[:path] = 'public/system/:class/:attachment/:id_partition/:style/:filename'
|
24
20
|
Paperclip::Attachment.default_options[:aliyun] = OSS_CONNECTION_OPTIONS
|
25
|
-
Paperclip::Attachment.default_options[:
|
21
|
+
Paperclip::Attachment.default_options[:path] = 'public/system/:class/:attachment/:id_partition/:style/:filename'
|
22
|
+
Paperclip::Attachment.default_options[:url] = ':aliyun_upload_url'
|
26
23
|
|
24
|
+
# Utility methods
|
27
25
|
def load_attachment(file_name)
|
28
|
-
File.open
|
26
|
+
File.open(Bundler.root.join("spec/attachments/#{file_name}"), 'rb')
|
29
27
|
end
|
data/spec/support/post.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require 'active_record'
|
2
|
+
require 'nulldb'
|
3
|
+
require 'paperclip'
|
4
4
|
|
5
5
|
class Post < ActiveRecord::Base
|
6
6
|
include Paperclip::Glue
|
@@ -11,10 +11,10 @@ end
|
|
11
11
|
|
12
12
|
RSpec.configure do |config|
|
13
13
|
config.before(:all) do
|
14
|
-
FileUtils.mkdir_p File.join(Bundler.root,
|
14
|
+
FileUtils.mkdir_p File.join(Bundler.root, 'tmp')
|
15
15
|
ActiveRecord::Base.establish_connection(
|
16
|
-
adapter:
|
17
|
-
schema: File.join(Bundler.root,
|
16
|
+
adapter: 'nulldb',
|
17
|
+
schema: File.join(Bundler.root, 'spec/fixtures/schema.rb')
|
18
18
|
)
|
19
19
|
end
|
20
20
|
|
data/spec/support/rails.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paperclip-storage-aliyun
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Hong
|
8
|
+
- Aidi Stan
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2015-
|
12
|
+
date: 2015-11-01 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: paperclip
|
@@ -44,8 +45,10 @@ executables: []
|
|
44
45
|
extensions: []
|
45
46
|
extra_rdoc_files: []
|
46
47
|
files:
|
48
|
+
- ".editorconfig"
|
47
49
|
- ".gitignore"
|
48
50
|
- ".rspec"
|
51
|
+
- ".rubocop.yml"
|
49
52
|
- Gemfile
|
50
53
|
- README.md
|
51
54
|
- lib/aliyun/connection.rb
|