activestorage-aliyun-oss 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 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: []