paperclip-storage-aliyun 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|