activestorage-aliyun-oss 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 846fe944de46bf6c077edbb456ff894aa1fb19ba
4
+ data.tar.gz: 88447903a5ad8b3b62e5c57212b9b7448f292bdf
5
+ SHA512:
6
+ metadata.gz: eccccb84caac1bd05abc4ddc1da341efe0eeefb842d78736e377147c1e18c9a7df3f34f4fa05f40e55f159631dc2ef8bf9d5ef610fadfdb8381337b888715bb0
7
+ data.tar.gz: c471d3b5025a4e4ea4c22b71fcd549bcd34d9e435f8ac6301e779cdaac7422b5f6f6bcadabeda4fdfd9b709b36f44fbc0b27e8011b6fd4a2a65c02c134875303
data/CHANGELOG.md ADDED
@@ -0,0 +1,29 @@
1
+ ## 0.4.0
2
+
3
+ - Support present `params` to `service_url` to oss image url.
4
+
5
+ for example:
6
+
7
+ ```rb
8
+ @photo.image.service_url(params: { 'x-oss-process' => "image/resize,h_100,w_100" })
9
+ ```
10
+
11
+ ## 0.3.0
12
+
13
+ - Add `mode` config for setup OSS ACL, `mode: "private"` will always output URL that have signature info.
14
+ - Support `disposition: :attachment` option for `service_url` method for download original filename.
15
+
16
+ ## 0.2.0
17
+
18
+ - Add url_for_direct_upload support.
19
+ - Fix delete_prefixed error when path not exists.
20
+
21
+ ## 0.1.1
22
+
23
+ - Fix streaming upload.
24
+ - Fix delete by prefixed.
25
+ - Add full test.
26
+
27
+ ## 0.1.0
28
+
29
+ - First release.
data/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # ActiveStorage Aliyun Service
2
+
3
+ Wraps the Aliyun OSS as an Active Storage service.
4
+
5
+
6
+ [![Gem Version](https://badge.fury.io/rb/activestorage-aliyun.svg)](https://badge.fury.io/rb/activestorage-aliyun) [![Build Status](https://travis-ci.org/huacnlee/activestorage-aliyun.svg)](https://travis-ci.org/huacnlee/activestorage-aliyun) [![Code Climate](https://codeclimate.com/github/huacnlee/activestorage-aliyun/badges/gpa.svg)](https://codeclimate.com/github/huacnlee/activestorage-aliyun) [![codecov.io](https://codecov.io/github/huacnlee/activestorage-aliyun/coverage.svg?branch=master)](https://codecov.io/github/huacnlee/activestorage-aliyun?branch=master)
7
+
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'activestorage-aliyun'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ ```bash
20
+ $ bundle
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ config/storage.yml
26
+
27
+ ```rb
28
+ production:
29
+ service: Aliyun
30
+ access_key_id: "your-oss-access-key-id"
31
+ access_key_secret: "your-oss-access-key-secret"
32
+ bucket: "bucket-name"
33
+ endpoint: "https://oss-cn-beijing.aliyuncs.com"
34
+ # path prefix, default: /
35
+ path: "my-app-files"
36
+ # Bucket mode: [public, private], default: public
37
+ mode: "public"
38
+ ```
39
+
40
+ ### Use for image url
41
+
42
+ ```erb
43
+ Orignial File URL:
44
+
45
+ <%= image_tag @photo.image.service_url %>
46
+ ```
47
+
48
+ Thumb with OSS image service:
49
+
50
+ ```rb
51
+ class Photo < ApplicationRecord
52
+ def image_thumb_url(process)
53
+ self.image.service_url(params: { "x-oss-process" => process })
54
+ end
55
+ end
56
+ ```
57
+
58
+ And then:
59
+
60
+ ```erb
61
+ <%= image_tag @photo.image.image_thumb_url("image/resize,h_100,w_100") %>
62
+ ```
63
+
64
+ ### Use for file download
65
+
66
+ If you want to get original filename (Include Chinese and other UTF-8 chars), for example: `演示文件 download.zip`, you need present `disposition: :attachment` option.
67
+
68
+ ```erb
69
+ #
70
+ <%= image_tag @photo.image.service_url(disposition: :attachment) %>
71
+ ```
72
+
73
+ ## Contributing
74
+
75
+ Contribution directions go here.
76
+
77
+ ## License
78
+
79
+ 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,27 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'ActiveStorage Aliyun Service'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ require 'bundler/gem_tasks'
18
+
19
+ require 'rake/testtask'
20
+
21
+ Rake::TestTask.new(:test) do |t|
22
+ t.libs << 'test'
23
+ t.pattern = 'test/**/*_test.rb'
24
+ t.verbose = false
25
+ end
26
+
27
+ task default: :test
@@ -0,0 +1,178 @@
1
+ # frozen_string_literal: true
2
+ require "aliyun/oss"
3
+
4
+ module ActiveStorage
5
+ class Service::AliyunService < Service
6
+ def initialize(**config)
7
+ Aliyun::Common::Logging.set_log_file("/dev/null")
8
+ @config = config
9
+ end
10
+
11
+ def upload(key, io, checksum: nil)
12
+ instrument :upload, key: key, checksum: checksum do
13
+ bucket.put_object(path_for(key)) do |stream|
14
+ stream << io.read
15
+ end
16
+ end
17
+ end
18
+
19
+ def download(key)
20
+ instrument :download, key: key do
21
+ chunk_buff = []
22
+ bucket.get_object(path_for(key)) do |chunk|
23
+ if block_given?
24
+ yield chunk
25
+ else
26
+ chunk_buff << chunk
27
+ end
28
+ end
29
+ chunk_buff.join("")
30
+ end
31
+ end
32
+
33
+ def download_chunk(key, range)
34
+ instrument :download_chunk, key: key, range: range do
35
+ uri = URI(url(key, expires_in: 30.seconds, filename: ActiveStorage::Filename.new(""), content_type: "application/octet-stream", disposition: "inline"))
36
+
37
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |client|
38
+ client.get(uri, "Range" => "bytes=#{range.begin}-#{range.exclude_end? ? range.end - 1 : range.end}").body
39
+ end
40
+ end
41
+ end
42
+
43
+ def delete(key)
44
+ instrument :delete, key: key do
45
+ bucket.delete_object(path_for(key))
46
+ end
47
+ end
48
+
49
+ def delete_prefixed(prefix)
50
+ instrument :delete_prefixed, prefix: prefix do
51
+ files = bucket.list_objects(prefix: path_for(prefix))
52
+ return if files.blank?
53
+ keys = files.map(&:key)
54
+ return if keys.blank?
55
+ bucket.batch_delete_objects(keys, quiet: true)
56
+ end
57
+ end
58
+
59
+ def exist?(key)
60
+ instrument :exist, key: key do |payload|
61
+ bucket.object_exists?(path_for(key))
62
+ end
63
+ end
64
+
65
+ def url(key, expires_in:, filename: nil, content_type:, disposition:, params: {})
66
+ instrument :url, key: key do |payload|
67
+ sign = private_mode? || disposition == :attachment
68
+ filekey = path_for(filename.to_s)
69
+
70
+ if disposition == :attachment
71
+ params["response-content-type"] = content_type if content_type
72
+ unless filename.is_a?(ActiveStorage::Filename)
73
+ filename = ActiveStorage::Filename.new(filename)
74
+ end
75
+
76
+ params["response-content-disposition"] = content_disposition_with(type: disposition, filename: filename)
77
+ end
78
+
79
+ generated_url = object_url(filekey, sign: sign, expires_in: expires_in, params: params)
80
+ payload[:url] = generated_url
81
+ generated_url
82
+ end
83
+ end
84
+
85
+ # You must setup CORS on OSS control panel to allow JavaScript request from your site domain.
86
+ # https://www.alibabacloud.com/help/zh/doc-detail/31988.htm
87
+ # https://help.aliyun.com/document_detail/31925.html
88
+ # Source: *.your.host.com
89
+ # Allowed Methods: POST, PUT, HEAD
90
+ # Allowed Headers: *
91
+ def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:)
92
+ instrument :url, key: key do |payload|
93
+ generated_url = bucket.object_url(path_for(key), false)
94
+ payload[:url] = generated_url
95
+ generated_url
96
+ end
97
+ end
98
+
99
+ # Headers for Direct Upload
100
+ # https://help.aliyun.com/document_detail/31951.html
101
+ # headers["Date"] is required use x-oss-date instead
102
+ def headers_for_direct_upload(key, content_type:, checksum:, **)
103
+ date = Time.now.httpdate
104
+ {
105
+ "Content-Type" => content_type,
106
+ "Content-MD5" => checksum,
107
+ "Authorization" => authorization(key, content_type, checksum, date),
108
+ "x-oss-date" => date,
109
+ }
110
+ end
111
+
112
+ private
113
+ attr_reader :config
114
+
115
+ def path_for(key)
116
+ return key unless config.fetch(:path, nil)
117
+ File.join(config.fetch(:path), key)
118
+ end
119
+
120
+ def object_url(key, sign:, expires_in: 60, params: {})
121
+ url = bucket.object_url(key, false)
122
+ unless sign
123
+ return url if params.blank?
124
+ return url + "?" + params.to_query
125
+ end
126
+
127
+ resource = "/#{bucket.name}/#{key}"
128
+ expires = Time.now.to_i + expires_in
129
+ query = {
130
+ "Expires" => expires,
131
+ "OSSAccessKeyId" => config.fetch(:access_key_id)
132
+ }
133
+ query.merge!(params)
134
+
135
+ if params.present?
136
+ resource += "?" + params.map { |k, v| "#{k}=#{v}" }.sort.join("&")
137
+ end
138
+
139
+ string_to_sign = ["GET", "", "", expires, resource].join("\n")
140
+ query["Signature"] = bucket.sign(string_to_sign)
141
+
142
+ [url, query.to_query].join('?')
143
+ end
144
+
145
+ def bucket
146
+ return @bucket if defined? @bucket
147
+ @bucket = client.get_bucket(config.fetch(:bucket))
148
+ @bucket
149
+ end
150
+
151
+ # Bucket mode :public | :private
152
+ def private_mode?
153
+ @private_mode ||= config.fetch(:mode, "public").to_s == "private"
154
+ end
155
+
156
+ def authorization(key, content_type, checksum, date)
157
+ filename = File.expand_path("/#{bucket.name}/#{path_for(key)}")
158
+ addition_headers = "x-oss-date:#{date}"
159
+ sign = ["PUT", checksum, content_type, date, addition_headers, filename].join("\n")
160
+ signature = bucket.sign(sign)
161
+ "OSS " + config.fetch(:access_key_id) + ":" + signature
162
+ end
163
+
164
+ def endpoint
165
+ config.fetch(:endpoint, "https://oss-cn-hangzhou.aliyuncs.com")
166
+ end
167
+
168
+ def client
169
+ @client ||= Aliyun::OSS::Client.new(
170
+ endpoint: endpoint,
171
+ access_key_id: config.fetch(:access_key_id),
172
+ access_key_secret: config.fetch(:access_key_secret),
173
+ cname: config.fetch(:cname, false)
174
+ )
175
+ end
176
+
177
+ end
178
+ end
@@ -0,0 +1,4 @@
1
+ module ActiveStorageAliyun
2
+ class Railtie < ::Rails::Railtie
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ module ActiveStorageAliyun
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,5 @@
1
+ # require "active_storage_aliyun/railtie"
2
+
3
+ module ActiveStorageAliyun
4
+ # Your code goes here...
5
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: activestorage-aliyun-oss
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Zhou
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-02-01 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.0
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.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: aliyun-sdk
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.6.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.6.0
41
+ description: Wraps the Aliyun OSS as an Active Storage service.
42
+ email: zhouchunyu20xx@163.com
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - CHANGELOG.md
48
+ - README.md
49
+ - Rakefile
50
+ - lib/active_storage/service/aliyun_service.rb
51
+ - lib/active_storage_aliyun/railtie.rb
52
+ - lib/active_storage_aliyun/version.rb
53
+ - lib/activestorage-aliyun.rb
54
+ homepage: https://github.com/huacnlee/activestorage-aliyun
55
+ licenses:
56
+ - MIT
57
+ metadata: {}
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubyforge_project:
74
+ rubygems_version: 2.4.5
75
+ signing_key:
76
+ specification_version: 4
77
+ summary: Wraps the Aliyun OSS as an Active Storage service
78
+ test_files: []