activestorage 5.2.0.rc1 → 5.2.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activestorage might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +37 -1
- data/README.md +1 -1
- data/app/assets/javascripts/activestorage.js +1 -1
- data/app/controllers/active_storage/{variants_controller.rb → representations_controller.rb} +3 -3
- data/app/javascript/activestorage/blob_upload.js +1 -1
- data/app/javascript/activestorage/direct_upload.js +6 -0
- data/app/models/active_storage/blob.rb +17 -4
- data/app/models/active_storage/blob/identifiable.rb +10 -1
- data/app/models/active_storage/blob/representable.rb +2 -2
- data/app/models/active_storage/filename.rb +10 -0
- data/app/models/active_storage/preview.rb +3 -4
- data/app/models/active_storage/variant.rb +1 -1
- data/app/models/active_storage/variation.rb +8 -0
- data/config/routes.rb +8 -20
- data/lib/active_storage/analyzer/image_analyzer.rb +11 -1
- data/lib/active_storage/attached/macros.rb +16 -2
- data/lib/active_storage/attached/many.rb +7 -11
- data/lib/active_storage/attached/one.rb +13 -14
- data/lib/active_storage/engine.rb +13 -4
- data/lib/active_storage/gem_version.rb +1 -1
- data/lib/active_storage/previewer/mupdf_previewer.rb +36 -0
- data/lib/active_storage/previewer/poppler_pdf_previewer.rb +35 -0
- data/lib/active_storage/service.rb +5 -0
- data/lib/active_storage/service/azure_storage_service.rb +19 -10
- data/lib/active_storage/service/disk_service.rb +21 -7
- data/lib/active_storage/service/gcs_service.rb +17 -5
- data/lib/active_storage/service/mirror_service.rb +1 -1
- data/lib/active_storage/service/s3_service.rb +8 -2
- metadata +12 -27
- data/app/controllers/active_storage/previews_controller.rb +0 -10
- data/app/models/active_storage/identification.rb +0 -38
- data/lib/active_storage/previewer/pdf_previewer.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 33c951e662aecba7002316ed527639dd5d34fbd6ee8e9fc4761b5340a1f8921e
|
4
|
+
data.tar.gz: 2de8ce856d601c374b412f6cfe1fcfe350676cbfa82194c081a6ca4508057247
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d5f44e8b8a474f1cc391f3875d232c44dbd676199733f2522d9bbe3a6da65041868dca229f921fa2ecf654b12fb277fdfa3ed0ec5972cc11893ab53824fbd15f
|
7
|
+
data.tar.gz: 95126d61ada21c590de7f0cf4da8a76c202a7f500283429e60871e2a0f286b5cf1aab200c9459782f795bdb6684e22179c94d6237787a94a9749fdcf44089d22
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,40 @@
|
|
1
|
+
## Rails 5.2.0.rc2 (March 20, 2018) ##
|
2
|
+
|
3
|
+
* Allow full use of the AWS S3 SDK options for authentication. If an
|
4
|
+
explicit AWS key pair and/or region is not provided in `storage.yml`,
|
5
|
+
attempt to use environment variables, shared credentials, or IAM
|
6
|
+
(instance or task) role credentials. Order of precedence is determined
|
7
|
+
by the [AWS SDK](https://docs.aws.amazon.com/sdk-for-ruby/v3/developer-guide/setup-config.html).
|
8
|
+
|
9
|
+
*Brian Knight*
|
10
|
+
|
11
|
+
* Remove path config option from Azure service.
|
12
|
+
|
13
|
+
The Active Storage service for Azure Storage has an option called `path`
|
14
|
+
that is ambiguous in meaning. It needs to be set to the primary blob
|
15
|
+
storage endpoint but that can be determined from the blobs client anyway.
|
16
|
+
|
17
|
+
To simplify the configuration, we've removed the `path` option and
|
18
|
+
now get the endpoint from the blobs client instead.
|
19
|
+
|
20
|
+
Closes #32225.
|
21
|
+
|
22
|
+
*Andrew White*
|
23
|
+
|
24
|
+
* Generate root-relative paths in disk service URL methods.
|
25
|
+
|
26
|
+
Obviate the disk service's `:host` configuration option.
|
27
|
+
|
28
|
+
*George Claghorn*
|
29
|
+
|
30
|
+
* Add source code to published npm package.
|
31
|
+
|
32
|
+
This allows activestorage users to depend on the javascript source code
|
33
|
+
rather than the compiled code, which can produce smaller javascript bundles.
|
34
|
+
|
35
|
+
*Richard Macklin*
|
36
|
+
|
37
|
+
|
1
38
|
## Rails 5.2.0.rc1 (January 30, 2018) ##
|
2
39
|
|
3
40
|
* Preserve display aspect ratio when extracting width and height from videos
|
@@ -14,7 +51,6 @@
|
|
14
51
|
|
15
52
|
*Hiroki Zenigami*
|
16
53
|
|
17
|
-
|
18
54
|
* Force `:attachment` disposition for specific, configurable content types.
|
19
55
|
This mitigates possible security issues such as XSS or phishing when
|
20
56
|
serving them inline. A list of such content types is included by default,
|
data/README.md
CHANGED
@@ -8,7 +8,7 @@ Image files can furthermore be transformed using on-demand variants for quality,
|
|
8
8
|
|
9
9
|
## Compared to other storage solutions
|
10
10
|
|
11
|
-
A key difference to how Active Storage works compared to other attachment solutions in Rails is through the use of built-in [Blob](https://github.com/rails/rails/blob/
|
11
|
+
A key difference to how Active Storage works compared to other attachment solutions in Rails is through the use of built-in [Blob](https://github.com/rails/rails/blob/5-2-stable/activestorage/app/models/active_storage/blob.rb) and [Attachment](https://github.com/rails/rails/blob/5-2-stable/activestorage/app/models/active_storage/attachment.rb) models (backed by Active Record). This means existing application models do not need to be modified with additional columns to associate with files. Active Storage uses polymorphic associations via the `Attachment` join model, which then connects to the actual `Blob`.
|
12
12
|
|
13
13
|
`Blob` models store attachment metadata (filename, content-type, etc.), and their identifier key in the storage service. Blob models do not store the actual binary data. They are intended to be immutable in spirit. One file, one blob. You can associate the same blob with multiple application models as well. And if you want to do transformations of a given `Blob`, the idea is that you'll simply create a new one, rather than attempt to mutate the existing one (though of course you can delete the previous version later if you don't need it).
|
14
14
|
|
@@ -1 +1 @@
|
|
1
|
-
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ActiveStorage=e():t.ActiveStorage=e()}(this,function(){return function(t){function e(n){if(r[n])return r[n].exports;var i=r[n]={i:n,l:!1,exports:{}};return t[n].call(i.exports,i,i.exports,e),i.l=!0,i.exports}var r={};return e.m=t,e.c=r,e.d=function(t,r,n){e.o(t,r)||Object.defineProperty(t,r,{configurable:!1,enumerable:!0,get:n})},e.n=function(t){var r=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(r,"a",r),r},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=2)}([function(t,e,r){"use strict";function n(t){var e=a(document.head,'meta[name="'+t+'"]');if(e)return e.getAttribute("content")}function i(t,e){return"string"==typeof t&&(e=t,t=document),o(t.querySelectorAll(e))}function a(t,e){return"string"==typeof t&&(e=t,t=document),t.querySelector(e)}function u(t,e){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},n=t.disabled,i=r.bubbles,a=r.cancelable,u=r.detail,o=document.createEvent("Event");o.initEvent(e,i||!0,a||!0),o.detail=u||{};try{t.disabled=!1,t.dispatchEvent(o)}finally{t.disabled=n}return o}function o(t){return Array.isArray(t)?t:Array.from?Array.from(t):[].slice.call(t)}e.d=n,e.c=i,e.b=a,e.a=u,e.e=o},function(t,e,r){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(t&&"function"==typeof t[e]){for(var r=arguments.length,n=Array(r>2?r-2:0),i=2;i<r;i++)n[i-2]=arguments[i];return t[e].apply(t,n)}}r.d(e,"a",function(){return c});var a=r(6),u=r(8),o=r(9),s=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),f=0,c=function(){function t(e,r,i){n(this,t),this.id=++f,this.file=e,this.url=r,this.delegate=i}return s(t,[{key:"create",value:function(t){var e=this;a.a.create(this.file,function(r,n){var a=new u.a(e.file,n,e.url);i(e.delegate,"directUploadWillCreateBlobWithXHR",a.xhr),a.create(function(r){if(r)t(r);else{var n=new o.a(a);i(e.delegate,"directUploadWillStoreFileWithXHR",n.xhr),n.create(function(e){e?t(e):t(null,a.toJSON())})}})})}}]),t}()},function(t,e,r){"use strict";function n(){window.ActiveStorage&&Object(i.a)()}Object.defineProperty(e,"__esModule",{value:!0});var i=r(3),a=r(1);r.d(e,"start",function(){return i.a}),r.d(e,"DirectUpload",function(){return a.a}),setTimeout(n,1)},function(t,e,r){"use strict";function n(){d||(d=!0,document.addEventListener("submit",i),document.addEventListener("ajax:before",a))}function i(t){u(t)}function a(t){"FORM"==t.target.tagName&&u(t)}function u(t){var e=t.target;if(e.hasAttribute(l))return void t.preventDefault();var r=new c.a(e),n=r.inputs;n.length&&(t.preventDefault(),e.setAttribute(l,""),n.forEach(s),r.start(function(t){e.removeAttribute(l),t?n.forEach(f):o(e)}))}function o(t){var e=Object(h.b)(t,"input[type=submit]");if(e){var r=e,n=r.disabled;e.disabled=!1,e.focus(),e.click(),e.disabled=n}else e=document.createElement("input"),e.type="submit",e.style="display:none",t.appendChild(e),e.click(),t.removeChild(e)}function s(t){t.disabled=!0}function f(t){t.disabled=!1}e.a=n;var c=r(4),h=r(0),l="data-direct-uploads-processing",d=!1},function(t,e,r){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}r.d(e,"a",function(){return s});var i=r(5),a=r(0),u=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),o="input[type=file][data-direct-upload-url]:not([disabled])",s=function(){function t(e){n(this,t),this.form=e,this.inputs=Object(a.c)(e,o).filter(function(t){return t.files.length})}return u(t,[{key:"start",value:function(t){var e=this,r=this.createDirectUploadControllers();this.dispatch("start"),function n(){var i=r.shift();i?i.start(function(r){r?(t(r),e.dispatch("end")):n()}):(t(),e.dispatch("end"))}()}},{key:"createDirectUploadControllers",value:function(){var t=[];return this.inputs.forEach(function(e){Object(a.e)(e.files).forEach(function(r){var n=new i.a(e,r);t.push(n)})}),t}},{key:"dispatch",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return Object(a.a)(this.form,"direct-uploads:"+t,{detail:e})}}]),t}()},function(t,e,r){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}r.d(e,"a",function(){return o});var i=r(1),a=r(0),u=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),o=function(){function t(e,r){n(this,t),this.input=e,this.file=r,this.directUpload=new i.a(this.file,this.url,this),this.dispatch("initialize")}return u(t,[{key:"start",value:function(t){var e=this,r=document.createElement("input");r.type="hidden",r.name=this.input.name,this.input.insertAdjacentElement("beforebegin",r),this.dispatch("start"),this.directUpload.create(function(n,i){n?(r.parentNode.removeChild(r),e.dispatchError(n)):r.value=i.signed_id,e.dispatch("end"),t(n)})}},{key:"uploadRequestDidProgress",value:function(t){var e=t.loaded/t.total*100;e&&this.dispatch("progress",{progress:e})}},{key:"dispatch",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.file=this.file,e.id=this.directUpload.id,Object(a.a)(this.input,"direct-upload:"+t,{detail:e})}},{key:"dispatchError",value:function(t){this.dispatch("error",{error:t}).defaultPrevented||alert(t)}},{key:"directUploadWillCreateBlobWithXHR",value:function(t){this.dispatch("before-blob-request",{xhr:t})}},{key:"directUploadWillStoreFileWithXHR",value:function(t){var e=this;this.dispatch("before-storage-request",{xhr:t}),t.upload.addEventListener("progress",function(t){return e.uploadRequestDidProgress(t)})}},{key:"url",get:function(){return this.input.getAttribute("data-direct-upload-url")}}]),t}()},function(t,e,r){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}r.d(e,"a",function(){return s});var i=r(7),a=r.n(i),u=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),o=File.prototype.slice||File.prototype.mozSlice||File.prototype.webkitSlice,s=function(){function t(e){n(this,t),this.file=e,this.chunkSize=2097152,this.chunkCount=Math.ceil(this.file.size/this.chunkSize),this.chunkIndex=0}return u(t,null,[{key:"create",value:function(e,r){new t(e).create(r)}}]),u(t,[{key:"create",value:function(t){var e=this;this.callback=t,this.md5Buffer=new a.a.ArrayBuffer,this.fileReader=new FileReader,this.fileReader.addEventListener("load",function(t){return e.fileReaderDidLoad(t)}),this.fileReader.addEventListener("error",function(t){return e.fileReaderDidError(t)}),this.readNextChunk()}},{key:"fileReaderDidLoad",value:function(t){if(this.md5Buffer.append(t.target.result),!this.readNextChunk()){var e=this.md5Buffer.end(!0),r=btoa(e);this.callback(null,r)}}},{key:"fileReaderDidError",value:function(t){this.callback("Error reading "+this.file.name)}},{key:"readNextChunk",value:function(){if(this.chunkIndex<this.chunkCount){var t=this.chunkIndex*this.chunkSize,e=Math.min(t+this.chunkSize,this.file.size),r=o.call(this.file,t,e);return this.fileReader.readAsArrayBuffer(r),this.chunkIndex++,!0}return!1}}]),t}()},function(t,e,r){!function(e){t.exports=e()}(function(t){"use strict";function e(t,e){var r=t[0],n=t[1],i=t[2],a=t[3];r+=(n&i|~n&a)+e[0]-680876936|0,r=(r<<7|r>>>25)+n|0,a+=(r&n|~r&i)+e[1]-389564586|0,a=(a<<12|a>>>20)+r|0,i+=(a&r|~a&n)+e[2]+606105819|0,i=(i<<17|i>>>15)+a|0,n+=(i&a|~i&r)+e[3]-1044525330|0,n=(n<<22|n>>>10)+i|0,r+=(n&i|~n&a)+e[4]-176418897|0,r=(r<<7|r>>>25)+n|0,a+=(r&n|~r&i)+e[5]+1200080426|0,a=(a<<12|a>>>20)+r|0,i+=(a&r|~a&n)+e[6]-1473231341|0,i=(i<<17|i>>>15)+a|0,n+=(i&a|~i&r)+e[7]-45705983|0,n=(n<<22|n>>>10)+i|0,r+=(n&i|~n&a)+e[8]+1770035416|0,r=(r<<7|r>>>25)+n|0,a+=(r&n|~r&i)+e[9]-1958414417|0,a=(a<<12|a>>>20)+r|0,i+=(a&r|~a&n)+e[10]-42063|0,i=(i<<17|i>>>15)+a|0,n+=(i&a|~i&r)+e[11]-1990404162|0,n=(n<<22|n>>>10)+i|0,r+=(n&i|~n&a)+e[12]+1804603682|0,r=(r<<7|r>>>25)+n|0,a+=(r&n|~r&i)+e[13]-40341101|0,a=(a<<12|a>>>20)+r|0,i+=(a&r|~a&n)+e[14]-1502002290|0,i=(i<<17|i>>>15)+a|0,n+=(i&a|~i&r)+e[15]+1236535329|0,n=(n<<22|n>>>10)+i|0,r+=(n&a|i&~a)+e[1]-165796510|0,r=(r<<5|r>>>27)+n|0,a+=(r&i|n&~i)+e[6]-1069501632|0,a=(a<<9|a>>>23)+r|0,i+=(a&n|r&~n)+e[11]+643717713|0,i=(i<<14|i>>>18)+a|0,n+=(i&r|a&~r)+e[0]-373897302|0,n=(n<<20|n>>>12)+i|0,r+=(n&a|i&~a)+e[5]-701558691|0,r=(r<<5|r>>>27)+n|0,a+=(r&i|n&~i)+e[10]+38016083|0,a=(a<<9|a>>>23)+r|0,i+=(a&n|r&~n)+e[15]-660478335|0,i=(i<<14|i>>>18)+a|0,n+=(i&r|a&~r)+e[4]-405537848|0,n=(n<<20|n>>>12)+i|0,r+=(n&a|i&~a)+e[9]+568446438|0,r=(r<<5|r>>>27)+n|0,a+=(r&i|n&~i)+e[14]-1019803690|0,a=(a<<9|a>>>23)+r|0,i+=(a&n|r&~n)+e[3]-187363961|0,i=(i<<14|i>>>18)+a|0,n+=(i&r|a&~r)+e[8]+1163531501|0,n=(n<<20|n>>>12)+i|0,r+=(n&a|i&~a)+e[13]-1444681467|0,r=(r<<5|r>>>27)+n|0,a+=(r&i|n&~i)+e[2]-51403784|0,a=(a<<9|a>>>23)+r|0,i+=(a&n|r&~n)+e[7]+1735328473|0,i=(i<<14|i>>>18)+a|0,n+=(i&r|a&~r)+e[12]-1926607734|0,n=(n<<20|n>>>12)+i|0,r+=(n^i^a)+e[5]-378558|0,r=(r<<4|r>>>28)+n|0,a+=(r^n^i)+e[8]-2022574463|0,a=(a<<11|a>>>21)+r|0,i+=(a^r^n)+e[11]+1839030562|0,i=(i<<16|i>>>16)+a|0,n+=(i^a^r)+e[14]-35309556|0,n=(n<<23|n>>>9)+i|0,r+=(n^i^a)+e[1]-1530992060|0,r=(r<<4|r>>>28)+n|0,a+=(r^n^i)+e[4]+1272893353|0,a=(a<<11|a>>>21)+r|0,i+=(a^r^n)+e[7]-155497632|0,i=(i<<16|i>>>16)+a|0,n+=(i^a^r)+e[10]-1094730640|0,n=(n<<23|n>>>9)+i|0,r+=(n^i^a)+e[13]+681279174|0,r=(r<<4|r>>>28)+n|0,a+=(r^n^i)+e[0]-358537222|0,a=(a<<11|a>>>21)+r|0,i+=(a^r^n)+e[3]-722521979|0,i=(i<<16|i>>>16)+a|0,n+=(i^a^r)+e[6]+76029189|0,n=(n<<23|n>>>9)+i|0,r+=(n^i^a)+e[9]-640364487|0,r=(r<<4|r>>>28)+n|0,a+=(r^n^i)+e[12]-421815835|0,a=(a<<11|a>>>21)+r|0,i+=(a^r^n)+e[15]+530742520|0,i=(i<<16|i>>>16)+a|0,n+=(i^a^r)+e[2]-995338651|0,n=(n<<23|n>>>9)+i|0,r+=(i^(n|~a))+e[0]-198630844|0,r=(r<<6|r>>>26)+n|0,a+=(n^(r|~i))+e[7]+1126891415|0,a=(a<<10|a>>>22)+r|0,i+=(r^(a|~n))+e[14]-1416354905|0,i=(i<<15|i>>>17)+a|0,n+=(a^(i|~r))+e[5]-57434055|0,n=(n<<21|n>>>11)+i|0,r+=(i^(n|~a))+e[12]+1700485571|0,r=(r<<6|r>>>26)+n|0,a+=(n^(r|~i))+e[3]-1894986606|0,a=(a<<10|a>>>22)+r|0,i+=(r^(a|~n))+e[10]-1051523|0,i=(i<<15|i>>>17)+a|0,n+=(a^(i|~r))+e[1]-2054922799|0,n=(n<<21|n>>>11)+i|0,r+=(i^(n|~a))+e[8]+1873313359|0,r=(r<<6|r>>>26)+n|0,a+=(n^(r|~i))+e[15]-30611744|0,a=(a<<10|a>>>22)+r|0,i+=(r^(a|~n))+e[6]-1560198380|0,i=(i<<15|i>>>17)+a|0,n+=(a^(i|~r))+e[13]+1309151649|0,n=(n<<21|n>>>11)+i|0,r+=(i^(n|~a))+e[4]-145523070|0,r=(r<<6|r>>>26)+n|0,a+=(n^(r|~i))+e[11]-1120210379|0,a=(a<<10|a>>>22)+r|0,i+=(r^(a|~n))+e[2]+718787259|0,i=(i<<15|i>>>17)+a|0,n+=(a^(i|~r))+e[9]-343485551|0,n=(n<<21|n>>>11)+i|0,t[0]=r+t[0]|0,t[1]=n+t[1]|0,t[2]=i+t[2]|0,t[3]=a+t[3]|0}function r(t){var e,r=[];for(e=0;e<64;e+=4)r[e>>2]=t.charCodeAt(e)+(t.charCodeAt(e+1)<<8)+(t.charCodeAt(e+2)<<16)+(t.charCodeAt(e+3)<<24);return r}function n(t){var e,r=[];for(e=0;e<64;e+=4)r[e>>2]=t[e]+(t[e+1]<<8)+(t[e+2]<<16)+(t[e+3]<<24);return r}function i(t){var n,i,a,u,o,s,f=t.length,c=[1732584193,-271733879,-1732584194,271733878];for(n=64;n<=f;n+=64)e(c,r(t.substring(n-64,n)));for(t=t.substring(n-64),i=t.length,a=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],n=0;n<i;n+=1)a[n>>2]|=t.charCodeAt(n)<<(n%4<<3);if(a[n>>2]|=128<<(n%4<<3),n>55)for(e(c,a),n=0;n<16;n+=1)a[n]=0;return u=8*f,u=u.toString(16).match(/(.*?)(.{0,8})$/),o=parseInt(u[2],16),s=parseInt(u[1],16)||0,a[14]=o,a[15]=s,e(c,a),c}function a(t){var r,i,a,u,o,s,f=t.length,c=[1732584193,-271733879,-1732584194,271733878];for(r=64;r<=f;r+=64)e(c,n(t.subarray(r-64,r)));for(t=r-64<f?t.subarray(r-64):new Uint8Array(0),i=t.length,a=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],r=0;r<i;r+=1)a[r>>2]|=t[r]<<(r%4<<3);if(a[r>>2]|=128<<(r%4<<3),r>55)for(e(c,a),r=0;r<16;r+=1)a[r]=0;return u=8*f,u=u.toString(16).match(/(.*?)(.{0,8})$/),o=parseInt(u[2],16),s=parseInt(u[1],16)||0,a[14]=o,a[15]=s,e(c,a),c}function u(t){var e,r="";for(e=0;e<4;e+=1)r+=p[t>>8*e+4&15]+p[t>>8*e&15];return r}function o(t){var e;for(e=0;e<t.length;e+=1)t[e]=u(t[e]);return t.join("")}function s(t){return/[\u0080-\uFFFF]/.test(t)&&(t=unescape(encodeURIComponent(t))),t}function f(t,e){var r,n=t.length,i=new ArrayBuffer(n),a=new Uint8Array(i);for(r=0;r<n;r+=1)a[r]=t.charCodeAt(r);return e?a:i}function c(t){return String.fromCharCode.apply(null,new Uint8Array(t))}function h(t,e,r){var n=new Uint8Array(t.byteLength+e.byteLength);return n.set(new Uint8Array(t)),n.set(new Uint8Array(e),t.byteLength),r?n:n.buffer}function l(t){var e,r=[],n=t.length;for(e=0;e<n-1;e+=2)r.push(parseInt(t.substr(e,2),16));return String.fromCharCode.apply(String,r)}function d(){this.reset()}var p=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];return"5d41402abc4b2a76b9719d911017c592"!==o(i("hello"))&&function(t,e){var r=(65535&t)+(65535&e);return(t>>16)+(e>>16)+(r>>16)<<16|65535&r},"undefined"==typeof ArrayBuffer||ArrayBuffer.prototype.slice||function(){function e(t,e){return t=0|t||0,t<0?Math.max(t+e,0):Math.min(t,e)}ArrayBuffer.prototype.slice=function(r,n){var i,a,u,o,s=this.byteLength,f=e(r,s),c=s;return n!==t&&(c=e(n,s)),f>c?new ArrayBuffer(0):(i=c-f,a=new ArrayBuffer(i),u=new Uint8Array(a),o=new Uint8Array(this,f,i),u.set(o),a)}}(),d.prototype.append=function(t){return this.appendBinary(s(t)),this},d.prototype.appendBinary=function(t){this._buff+=t,this._length+=t.length;var n,i=this._buff.length;for(n=64;n<=i;n+=64)e(this._hash,r(this._buff.substring(n-64,n)));return this._buff=this._buff.substring(n-64),this},d.prototype.end=function(t){var e,r,n=this._buff,i=n.length,a=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(e=0;e<i;e+=1)a[e>>2]|=n.charCodeAt(e)<<(e%4<<3);return this._finish(a,i),r=o(this._hash),t&&(r=l(r)),this.reset(),r},d.prototype.reset=function(){return this._buff="",this._length=0,this._hash=[1732584193,-271733879,-1732584194,271733878],this},d.prototype.getState=function(){return{buff:this._buff,length:this._length,hash:this._hash}},d.prototype.setState=function(t){return this._buff=t.buff,this._length=t.length,this._hash=t.hash,this},d.prototype.destroy=function(){delete this._hash,delete this._buff,delete this._length},d.prototype._finish=function(t,r){var n,i,a,u=r;if(t[u>>2]|=128<<(u%4<<3),u>55)for(e(this._hash,t),u=0;u<16;u+=1)t[u]=0;n=8*this._length,n=n.toString(16).match(/(.*?)(.{0,8})$/),i=parseInt(n[2],16),a=parseInt(n[1],16)||0,t[14]=i,t[15]=a,e(this._hash,t)},d.hash=function(t,e){return d.hashBinary(s(t),e)},d.hashBinary=function(t,e){var r=i(t),n=o(r);return e?l(n):n},d.ArrayBuffer=function(){this.reset()},d.ArrayBuffer.prototype.append=function(t){var r,i=h(this._buff.buffer,t,!0),a=i.length;for(this._length+=t.byteLength,r=64;r<=a;r+=64)e(this._hash,n(i.subarray(r-64,r)));return this._buff=r-64<a?new Uint8Array(i.buffer.slice(r-64)):new Uint8Array(0),this},d.ArrayBuffer.prototype.end=function(t){var e,r,n=this._buff,i=n.length,a=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(e=0;e<i;e+=1)a[e>>2]|=n[e]<<(e%4<<3);return this._finish(a,i),r=o(this._hash),t&&(r=l(r)),this.reset(),r},d.ArrayBuffer.prototype.reset=function(){return this._buff=new Uint8Array(0),this._length=0,this._hash=[1732584193,-271733879,-1732584194,271733878],this},d.ArrayBuffer.prototype.getState=function(){var t=d.prototype.getState.call(this);return t.buff=c(t.buff),t},d.ArrayBuffer.prototype.setState=function(t){return t.buff=f(t.buff,!0),d.prototype.setState.call(this,t)},d.ArrayBuffer.prototype.destroy=d.prototype.destroy,d.ArrayBuffer.prototype._finish=d.prototype._finish,d.ArrayBuffer.hash=function(t,e){var r=a(new Uint8Array(t)),n=o(r);return e?l(n):n},d})},function(t,e,r){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}r.d(e,"a",function(){return u});var i=r(0),a=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),u=function(){function t(e,r,a){var u=this;n(this,t),this.file=e,this.attributes={filename:e.name,content_type:e.type,byte_size:e.size,checksum:r},this.xhr=new XMLHttpRequest,this.xhr.open("POST",a,!0),this.xhr.responseType="json",this.xhr.setRequestHeader("Content-Type","application/json"),this.xhr.setRequestHeader("Accept","application/json"),this.xhr.setRequestHeader("X-Requested-With","XMLHttpRequest"),this.xhr.setRequestHeader("X-CSRF-Token",Object(i.d)("csrf-token")),this.xhr.addEventListener("load",function(t){return u.requestDidLoad(t)}),this.xhr.addEventListener("error",function(t){return u.requestDidError(t)})}return a(t,[{key:"create",value:function(t){this.callback=t,this.xhr.send(JSON.stringify({blob:this.attributes}))}},{key:"requestDidLoad",value:function(t){if(this.status>=200&&this.status<300){var e=this.response,r=e.direct_upload;delete e.direct_upload,this.attributes=e,this.directUploadData=r,this.callback(null,this.toJSON())}else this.requestDidError(t)}},{key:"requestDidError",value:function(t){this.callback('Error creating Blob for "'+this.file.name+'". Status: '+this.status)}},{key:"toJSON",value:function(){var t={};for(var e in this.attributes)t[e]=this.attributes[e];return t}},{key:"status",get:function(){return this.xhr.status}},{key:"response",get:function(){var t=this.xhr,e=t.responseType,r=t.response;return"json"==e?r:JSON.parse(r)}}]),t}()},function(t,e,r){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}r.d(e,"a",function(){return a});var i=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),a=function(){function t(e){var r=this;n(this,t),this.blob=e,this.file=e.file;var i=e.directUploadData,a=i.url,u=i.headers;this.xhr=new XMLHttpRequest,this.xhr.open("PUT",a,!0),this.xhr.responseType="text";for(var o in u)this.xhr.setRequestHeader(o,u[o]);this.xhr.addEventListener("load",function(t){return r.requestDidLoad(t)}),this.xhr.addEventListener("error",function(t){return r.requestDidError(t)})}return i(t,[{key:"create",value:function(t){this.callback=t,this.xhr.send(this.file)}},{key:"requestDidLoad",value:function(t){var e=this.xhr,r=e.status,n=e.response;r>=200&&r<300?this.callback(null,n):this.requestDidError(t)}},{key:"requestDidError",value:function(t){this.callback('Error storing "'+this.file.name+'". Status: '+this.xhr.status)}}]),t}()}])});
|
1
|
+
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ActiveStorage=e():t.ActiveStorage=e()}(this,function(){return function(t){function e(n){if(r[n])return r[n].exports;var i=r[n]={i:n,l:!1,exports:{}};return t[n].call(i.exports,i,i.exports,e),i.l=!0,i.exports}var r={};return e.m=t,e.c=r,e.d=function(t,r,n){e.o(t,r)||Object.defineProperty(t,r,{configurable:!1,enumerable:!0,get:n})},e.n=function(t){var r=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(r,"a",r),r},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=2)}([function(t,e,r){"use strict";function n(t){var e=a(document.head,'meta[name="'+t+'"]');if(e)return e.getAttribute("content")}function i(t,e){return"string"==typeof t&&(e=t,t=document),o(t.querySelectorAll(e))}function a(t,e){return"string"==typeof t&&(e=t,t=document),t.querySelector(e)}function u(t,e){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},n=t.disabled,i=r.bubbles,a=r.cancelable,u=r.detail,o=document.createEvent("Event");o.initEvent(e,i||!0,a||!0),o.detail=u||{};try{t.disabled=!1,t.dispatchEvent(o)}finally{t.disabled=n}return o}function o(t){return Array.isArray(t)?t:Array.from?Array.from(t):[].slice.call(t)}e.d=n,e.c=i,e.b=a,e.a=u,e.e=o},function(t,e,r){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(t&&"function"==typeof t[e]){for(var r=arguments.length,n=Array(r>2?r-2:0),i=2;i<r;i++)n[i-2]=arguments[i];return t[e].apply(t,n)}}r.d(e,"a",function(){return c});var a=r(6),u=r(8),o=r(9),s=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),f=0,c=function(){function t(e,r,i){n(this,t),this.id=++f,this.file=e,this.url=r,this.delegate=i}return s(t,[{key:"create",value:function(t){var e=this;a.a.create(this.file,function(r,n){if(r)return void t(r);var a=new u.a(e.file,n,e.url);i(e.delegate,"directUploadWillCreateBlobWithXHR",a.xhr),a.create(function(r){if(r)t(r);else{var n=new o.a(a);i(e.delegate,"directUploadWillStoreFileWithXHR",n.xhr),n.create(function(e){e?t(e):t(null,a.toJSON())})}})})}}]),t}()},function(t,e,r){"use strict";function n(){window.ActiveStorage&&Object(i.a)()}Object.defineProperty(e,"__esModule",{value:!0});var i=r(3),a=r(1);r.d(e,"start",function(){return i.a}),r.d(e,"DirectUpload",function(){return a.a}),setTimeout(n,1)},function(t,e,r){"use strict";function n(){d||(d=!0,document.addEventListener("submit",i),document.addEventListener("ajax:before",a))}function i(t){u(t)}function a(t){"FORM"==t.target.tagName&&u(t)}function u(t){var e=t.target;if(e.hasAttribute(l))return void t.preventDefault();var r=new c.a(e),n=r.inputs;n.length&&(t.preventDefault(),e.setAttribute(l,""),n.forEach(s),r.start(function(t){e.removeAttribute(l),t?n.forEach(f):o(e)}))}function o(t){var e=Object(h.b)(t,"input[type=submit]");if(e){var r=e,n=r.disabled;e.disabled=!1,e.focus(),e.click(),e.disabled=n}else e=document.createElement("input"),e.type="submit",e.style="display:none",t.appendChild(e),e.click(),t.removeChild(e)}function s(t){t.disabled=!0}function f(t){t.disabled=!1}e.a=n;var c=r(4),h=r(0),l="data-direct-uploads-processing",d=!1},function(t,e,r){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}r.d(e,"a",function(){return s});var i=r(5),a=r(0),u=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),o="input[type=file][data-direct-upload-url]:not([disabled])",s=function(){function t(e){n(this,t),this.form=e,this.inputs=Object(a.c)(e,o).filter(function(t){return t.files.length})}return u(t,[{key:"start",value:function(t){var e=this,r=this.createDirectUploadControllers();this.dispatch("start"),function n(){var i=r.shift();i?i.start(function(r){r?(t(r),e.dispatch("end")):n()}):(t(),e.dispatch("end"))}()}},{key:"createDirectUploadControllers",value:function(){var t=[];return this.inputs.forEach(function(e){Object(a.e)(e.files).forEach(function(r){var n=new i.a(e,r);t.push(n)})}),t}},{key:"dispatch",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return Object(a.a)(this.form,"direct-uploads:"+t,{detail:e})}}]),t}()},function(t,e,r){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}r.d(e,"a",function(){return o});var i=r(1),a=r(0),u=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),o=function(){function t(e,r){n(this,t),this.input=e,this.file=r,this.directUpload=new i.a(this.file,this.url,this),this.dispatch("initialize")}return u(t,[{key:"start",value:function(t){var e=this,r=document.createElement("input");r.type="hidden",r.name=this.input.name,this.input.insertAdjacentElement("beforebegin",r),this.dispatch("start"),this.directUpload.create(function(n,i){n?(r.parentNode.removeChild(r),e.dispatchError(n)):r.value=i.signed_id,e.dispatch("end"),t(n)})}},{key:"uploadRequestDidProgress",value:function(t){var e=t.loaded/t.total*100;e&&this.dispatch("progress",{progress:e})}},{key:"dispatch",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.file=this.file,e.id=this.directUpload.id,Object(a.a)(this.input,"direct-upload:"+t,{detail:e})}},{key:"dispatchError",value:function(t){this.dispatch("error",{error:t}).defaultPrevented||alert(t)}},{key:"directUploadWillCreateBlobWithXHR",value:function(t){this.dispatch("before-blob-request",{xhr:t})}},{key:"directUploadWillStoreFileWithXHR",value:function(t){var e=this;this.dispatch("before-storage-request",{xhr:t}),t.upload.addEventListener("progress",function(t){return e.uploadRequestDidProgress(t)})}},{key:"url",get:function(){return this.input.getAttribute("data-direct-upload-url")}}]),t}()},function(t,e,r){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}r.d(e,"a",function(){return s});var i=r(7),a=r.n(i),u=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),o=File.prototype.slice||File.prototype.mozSlice||File.prototype.webkitSlice,s=function(){function t(e){n(this,t),this.file=e,this.chunkSize=2097152,this.chunkCount=Math.ceil(this.file.size/this.chunkSize),this.chunkIndex=0}return u(t,null,[{key:"create",value:function(e,r){new t(e).create(r)}}]),u(t,[{key:"create",value:function(t){var e=this;this.callback=t,this.md5Buffer=new a.a.ArrayBuffer,this.fileReader=new FileReader,this.fileReader.addEventListener("load",function(t){return e.fileReaderDidLoad(t)}),this.fileReader.addEventListener("error",function(t){return e.fileReaderDidError(t)}),this.readNextChunk()}},{key:"fileReaderDidLoad",value:function(t){if(this.md5Buffer.append(t.target.result),!this.readNextChunk()){var e=this.md5Buffer.end(!0),r=btoa(e);this.callback(null,r)}}},{key:"fileReaderDidError",value:function(t){this.callback("Error reading "+this.file.name)}},{key:"readNextChunk",value:function(){if(this.chunkIndex<this.chunkCount){var t=this.chunkIndex*this.chunkSize,e=Math.min(t+this.chunkSize,this.file.size),r=o.call(this.file,t,e);return this.fileReader.readAsArrayBuffer(r),this.chunkIndex++,!0}return!1}}]),t}()},function(t,e,r){!function(e){t.exports=e()}(function(t){"use strict";function e(t,e){var r=t[0],n=t[1],i=t[2],a=t[3];r+=(n&i|~n&a)+e[0]-680876936|0,r=(r<<7|r>>>25)+n|0,a+=(r&n|~r&i)+e[1]-389564586|0,a=(a<<12|a>>>20)+r|0,i+=(a&r|~a&n)+e[2]+606105819|0,i=(i<<17|i>>>15)+a|0,n+=(i&a|~i&r)+e[3]-1044525330|0,n=(n<<22|n>>>10)+i|0,r+=(n&i|~n&a)+e[4]-176418897|0,r=(r<<7|r>>>25)+n|0,a+=(r&n|~r&i)+e[5]+1200080426|0,a=(a<<12|a>>>20)+r|0,i+=(a&r|~a&n)+e[6]-1473231341|0,i=(i<<17|i>>>15)+a|0,n+=(i&a|~i&r)+e[7]-45705983|0,n=(n<<22|n>>>10)+i|0,r+=(n&i|~n&a)+e[8]+1770035416|0,r=(r<<7|r>>>25)+n|0,a+=(r&n|~r&i)+e[9]-1958414417|0,a=(a<<12|a>>>20)+r|0,i+=(a&r|~a&n)+e[10]-42063|0,i=(i<<17|i>>>15)+a|0,n+=(i&a|~i&r)+e[11]-1990404162|0,n=(n<<22|n>>>10)+i|0,r+=(n&i|~n&a)+e[12]+1804603682|0,r=(r<<7|r>>>25)+n|0,a+=(r&n|~r&i)+e[13]-40341101|0,a=(a<<12|a>>>20)+r|0,i+=(a&r|~a&n)+e[14]-1502002290|0,i=(i<<17|i>>>15)+a|0,n+=(i&a|~i&r)+e[15]+1236535329|0,n=(n<<22|n>>>10)+i|0,r+=(n&a|i&~a)+e[1]-165796510|0,r=(r<<5|r>>>27)+n|0,a+=(r&i|n&~i)+e[6]-1069501632|0,a=(a<<9|a>>>23)+r|0,i+=(a&n|r&~n)+e[11]+643717713|0,i=(i<<14|i>>>18)+a|0,n+=(i&r|a&~r)+e[0]-373897302|0,n=(n<<20|n>>>12)+i|0,r+=(n&a|i&~a)+e[5]-701558691|0,r=(r<<5|r>>>27)+n|0,a+=(r&i|n&~i)+e[10]+38016083|0,a=(a<<9|a>>>23)+r|0,i+=(a&n|r&~n)+e[15]-660478335|0,i=(i<<14|i>>>18)+a|0,n+=(i&r|a&~r)+e[4]-405537848|0,n=(n<<20|n>>>12)+i|0,r+=(n&a|i&~a)+e[9]+568446438|0,r=(r<<5|r>>>27)+n|0,a+=(r&i|n&~i)+e[14]-1019803690|0,a=(a<<9|a>>>23)+r|0,i+=(a&n|r&~n)+e[3]-187363961|0,i=(i<<14|i>>>18)+a|0,n+=(i&r|a&~r)+e[8]+1163531501|0,n=(n<<20|n>>>12)+i|0,r+=(n&a|i&~a)+e[13]-1444681467|0,r=(r<<5|r>>>27)+n|0,a+=(r&i|n&~i)+e[2]-51403784|0,a=(a<<9|a>>>23)+r|0,i+=(a&n|r&~n)+e[7]+1735328473|0,i=(i<<14|i>>>18)+a|0,n+=(i&r|a&~r)+e[12]-1926607734|0,n=(n<<20|n>>>12)+i|0,r+=(n^i^a)+e[5]-378558|0,r=(r<<4|r>>>28)+n|0,a+=(r^n^i)+e[8]-2022574463|0,a=(a<<11|a>>>21)+r|0,i+=(a^r^n)+e[11]+1839030562|0,i=(i<<16|i>>>16)+a|0,n+=(i^a^r)+e[14]-35309556|0,n=(n<<23|n>>>9)+i|0,r+=(n^i^a)+e[1]-1530992060|0,r=(r<<4|r>>>28)+n|0,a+=(r^n^i)+e[4]+1272893353|0,a=(a<<11|a>>>21)+r|0,i+=(a^r^n)+e[7]-155497632|0,i=(i<<16|i>>>16)+a|0,n+=(i^a^r)+e[10]-1094730640|0,n=(n<<23|n>>>9)+i|0,r+=(n^i^a)+e[13]+681279174|0,r=(r<<4|r>>>28)+n|0,a+=(r^n^i)+e[0]-358537222|0,a=(a<<11|a>>>21)+r|0,i+=(a^r^n)+e[3]-722521979|0,i=(i<<16|i>>>16)+a|0,n+=(i^a^r)+e[6]+76029189|0,n=(n<<23|n>>>9)+i|0,r+=(n^i^a)+e[9]-640364487|0,r=(r<<4|r>>>28)+n|0,a+=(r^n^i)+e[12]-421815835|0,a=(a<<11|a>>>21)+r|0,i+=(a^r^n)+e[15]+530742520|0,i=(i<<16|i>>>16)+a|0,n+=(i^a^r)+e[2]-995338651|0,n=(n<<23|n>>>9)+i|0,r+=(i^(n|~a))+e[0]-198630844|0,r=(r<<6|r>>>26)+n|0,a+=(n^(r|~i))+e[7]+1126891415|0,a=(a<<10|a>>>22)+r|0,i+=(r^(a|~n))+e[14]-1416354905|0,i=(i<<15|i>>>17)+a|0,n+=(a^(i|~r))+e[5]-57434055|0,n=(n<<21|n>>>11)+i|0,r+=(i^(n|~a))+e[12]+1700485571|0,r=(r<<6|r>>>26)+n|0,a+=(n^(r|~i))+e[3]-1894986606|0,a=(a<<10|a>>>22)+r|0,i+=(r^(a|~n))+e[10]-1051523|0,i=(i<<15|i>>>17)+a|0,n+=(a^(i|~r))+e[1]-2054922799|0,n=(n<<21|n>>>11)+i|0,r+=(i^(n|~a))+e[8]+1873313359|0,r=(r<<6|r>>>26)+n|0,a+=(n^(r|~i))+e[15]-30611744|0,a=(a<<10|a>>>22)+r|0,i+=(r^(a|~n))+e[6]-1560198380|0,i=(i<<15|i>>>17)+a|0,n+=(a^(i|~r))+e[13]+1309151649|0,n=(n<<21|n>>>11)+i|0,r+=(i^(n|~a))+e[4]-145523070|0,r=(r<<6|r>>>26)+n|0,a+=(n^(r|~i))+e[11]-1120210379|0,a=(a<<10|a>>>22)+r|0,i+=(r^(a|~n))+e[2]+718787259|0,i=(i<<15|i>>>17)+a|0,n+=(a^(i|~r))+e[9]-343485551|0,n=(n<<21|n>>>11)+i|0,t[0]=r+t[0]|0,t[1]=n+t[1]|0,t[2]=i+t[2]|0,t[3]=a+t[3]|0}function r(t){var e,r=[];for(e=0;e<64;e+=4)r[e>>2]=t.charCodeAt(e)+(t.charCodeAt(e+1)<<8)+(t.charCodeAt(e+2)<<16)+(t.charCodeAt(e+3)<<24);return r}function n(t){var e,r=[];for(e=0;e<64;e+=4)r[e>>2]=t[e]+(t[e+1]<<8)+(t[e+2]<<16)+(t[e+3]<<24);return r}function i(t){var n,i,a,u,o,s,f=t.length,c=[1732584193,-271733879,-1732584194,271733878];for(n=64;n<=f;n+=64)e(c,r(t.substring(n-64,n)));for(t=t.substring(n-64),i=t.length,a=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],n=0;n<i;n+=1)a[n>>2]|=t.charCodeAt(n)<<(n%4<<3);if(a[n>>2]|=128<<(n%4<<3),n>55)for(e(c,a),n=0;n<16;n+=1)a[n]=0;return u=8*f,u=u.toString(16).match(/(.*?)(.{0,8})$/),o=parseInt(u[2],16),s=parseInt(u[1],16)||0,a[14]=o,a[15]=s,e(c,a),c}function a(t){var r,i,a,u,o,s,f=t.length,c=[1732584193,-271733879,-1732584194,271733878];for(r=64;r<=f;r+=64)e(c,n(t.subarray(r-64,r)));for(t=r-64<f?t.subarray(r-64):new Uint8Array(0),i=t.length,a=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],r=0;r<i;r+=1)a[r>>2]|=t[r]<<(r%4<<3);if(a[r>>2]|=128<<(r%4<<3),r>55)for(e(c,a),r=0;r<16;r+=1)a[r]=0;return u=8*f,u=u.toString(16).match(/(.*?)(.{0,8})$/),o=parseInt(u[2],16),s=parseInt(u[1],16)||0,a[14]=o,a[15]=s,e(c,a),c}function u(t){var e,r="";for(e=0;e<4;e+=1)r+=p[t>>8*e+4&15]+p[t>>8*e&15];return r}function o(t){var e;for(e=0;e<t.length;e+=1)t[e]=u(t[e]);return t.join("")}function s(t){return/[\u0080-\uFFFF]/.test(t)&&(t=unescape(encodeURIComponent(t))),t}function f(t,e){var r,n=t.length,i=new ArrayBuffer(n),a=new Uint8Array(i);for(r=0;r<n;r+=1)a[r]=t.charCodeAt(r);return e?a:i}function c(t){return String.fromCharCode.apply(null,new Uint8Array(t))}function h(t,e,r){var n=new Uint8Array(t.byteLength+e.byteLength);return n.set(new Uint8Array(t)),n.set(new Uint8Array(e),t.byteLength),r?n:n.buffer}function l(t){var e,r=[],n=t.length;for(e=0;e<n-1;e+=2)r.push(parseInt(t.substr(e,2),16));return String.fromCharCode.apply(String,r)}function d(){this.reset()}var p=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];return"5d41402abc4b2a76b9719d911017c592"!==o(i("hello"))&&function(t,e){var r=(65535&t)+(65535&e);return(t>>16)+(e>>16)+(r>>16)<<16|65535&r},"undefined"==typeof ArrayBuffer||ArrayBuffer.prototype.slice||function(){function e(t,e){return t=0|t||0,t<0?Math.max(t+e,0):Math.min(t,e)}ArrayBuffer.prototype.slice=function(r,n){var i,a,u,o,s=this.byteLength,f=e(r,s),c=s;return n!==t&&(c=e(n,s)),f>c?new ArrayBuffer(0):(i=c-f,a=new ArrayBuffer(i),u=new Uint8Array(a),o=new Uint8Array(this,f,i),u.set(o),a)}}(),d.prototype.append=function(t){return this.appendBinary(s(t)),this},d.prototype.appendBinary=function(t){this._buff+=t,this._length+=t.length;var n,i=this._buff.length;for(n=64;n<=i;n+=64)e(this._hash,r(this._buff.substring(n-64,n)));return this._buff=this._buff.substring(n-64),this},d.prototype.end=function(t){var e,r,n=this._buff,i=n.length,a=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(e=0;e<i;e+=1)a[e>>2]|=n.charCodeAt(e)<<(e%4<<3);return this._finish(a,i),r=o(this._hash),t&&(r=l(r)),this.reset(),r},d.prototype.reset=function(){return this._buff="",this._length=0,this._hash=[1732584193,-271733879,-1732584194,271733878],this},d.prototype.getState=function(){return{buff:this._buff,length:this._length,hash:this._hash}},d.prototype.setState=function(t){return this._buff=t.buff,this._length=t.length,this._hash=t.hash,this},d.prototype.destroy=function(){delete this._hash,delete this._buff,delete this._length},d.prototype._finish=function(t,r){var n,i,a,u=r;if(t[u>>2]|=128<<(u%4<<3),u>55)for(e(this._hash,t),u=0;u<16;u+=1)t[u]=0;n=8*this._length,n=n.toString(16).match(/(.*?)(.{0,8})$/),i=parseInt(n[2],16),a=parseInt(n[1],16)||0,t[14]=i,t[15]=a,e(this._hash,t)},d.hash=function(t,e){return d.hashBinary(s(t),e)},d.hashBinary=function(t,e){var r=i(t),n=o(r);return e?l(n):n},d.ArrayBuffer=function(){this.reset()},d.ArrayBuffer.prototype.append=function(t){var r,i=h(this._buff.buffer,t,!0),a=i.length;for(this._length+=t.byteLength,r=64;r<=a;r+=64)e(this._hash,n(i.subarray(r-64,r)));return this._buff=r-64<a?new Uint8Array(i.buffer.slice(r-64)):new Uint8Array(0),this},d.ArrayBuffer.prototype.end=function(t){var e,r,n=this._buff,i=n.length,a=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(e=0;e<i;e+=1)a[e>>2]|=n[e]<<(e%4<<3);return this._finish(a,i),r=o(this._hash),t&&(r=l(r)),this.reset(),r},d.ArrayBuffer.prototype.reset=function(){return this._buff=new Uint8Array(0),this._length=0,this._hash=[1732584193,-271733879,-1732584194,271733878],this},d.ArrayBuffer.prototype.getState=function(){var t=d.prototype.getState.call(this);return t.buff=c(t.buff),t},d.ArrayBuffer.prototype.setState=function(t){return t.buff=f(t.buff,!0),d.prototype.setState.call(this,t)},d.ArrayBuffer.prototype.destroy=d.prototype.destroy,d.ArrayBuffer.prototype._finish=d.prototype._finish,d.ArrayBuffer.hash=function(t,e){var r=a(new Uint8Array(t)),n=o(r);return e?l(n):n},d})},function(t,e,r){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}r.d(e,"a",function(){return u});var i=r(0),a=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),u=function(){function t(e,r,a){var u=this;n(this,t),this.file=e,this.attributes={filename:e.name,content_type:e.type,byte_size:e.size,checksum:r},this.xhr=new XMLHttpRequest,this.xhr.open("POST",a,!0),this.xhr.responseType="json",this.xhr.setRequestHeader("Content-Type","application/json"),this.xhr.setRequestHeader("Accept","application/json"),this.xhr.setRequestHeader("X-Requested-With","XMLHttpRequest"),this.xhr.setRequestHeader("X-CSRF-Token",Object(i.d)("csrf-token")),this.xhr.addEventListener("load",function(t){return u.requestDidLoad(t)}),this.xhr.addEventListener("error",function(t){return u.requestDidError(t)})}return a(t,[{key:"create",value:function(t){this.callback=t,this.xhr.send(JSON.stringify({blob:this.attributes}))}},{key:"requestDidLoad",value:function(t){if(this.status>=200&&this.status<300){var e=this.response,r=e.direct_upload;delete e.direct_upload,this.attributes=e,this.directUploadData=r,this.callback(null,this.toJSON())}else this.requestDidError(t)}},{key:"requestDidError",value:function(t){this.callback('Error creating Blob for "'+this.file.name+'". Status: '+this.status)}},{key:"toJSON",value:function(){var t={};for(var e in this.attributes)t[e]=this.attributes[e];return t}},{key:"status",get:function(){return this.xhr.status}},{key:"response",get:function(){var t=this.xhr,e=t.responseType,r=t.response;return"json"==e?r:JSON.parse(r)}}]),t}()},function(t,e,r){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}r.d(e,"a",function(){return a});var i=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),a=function(){function t(e){var r=this;n(this,t),this.blob=e,this.file=e.file;var i=e.directUploadData,a=i.url,u=i.headers;this.xhr=new XMLHttpRequest,this.xhr.open("PUT",a,!0),this.xhr.responseType="text";for(var o in u)this.xhr.setRequestHeader(o,u[o]);this.xhr.addEventListener("load",function(t){return r.requestDidLoad(t)}),this.xhr.addEventListener("error",function(t){return r.requestDidError(t)})}return i(t,[{key:"create",value:function(t){this.callback=t,this.xhr.send(this.file.slice())}},{key:"requestDidLoad",value:function(t){var e=this.xhr,r=e.status,n=e.response;r>=200&&r<300?this.callback(null,n):this.requestDidError(t)}},{key:"requestDidError",value:function(t){this.callback('Error storing "'+this.file.name+'". Status: '+this.xhr.status)}}]),t}()}])});
|
data/app/controllers/active_storage/{variants_controller.rb → representations_controller.rb}
RENAMED
@@ -1,14 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Take a signed permanent reference for a
|
3
|
+
# Take a signed permanent reference for a blob representation and turn it into an expiring service URL for download.
|
4
4
|
# Note: These URLs are publicly accessible. If you need to enforce access protection beyond the
|
5
5
|
# security-through-obscurity factor of the signed blob and variation reference, you'll need to implement your own
|
6
6
|
# authenticated redirection controller.
|
7
|
-
class ActiveStorage::
|
7
|
+
class ActiveStorage::RepresentationsController < ActionController::Base
|
8
8
|
include ActiveStorage::SetBlob
|
9
9
|
|
10
10
|
def show
|
11
11
|
expires_in ActiveStorage::Blob.service.url_expires_in
|
12
|
-
redirect_to
|
12
|
+
redirect_to @blob.representation(params[:variation_key]).processed.service_url(disposition: params[:disposition])
|
13
13
|
end
|
14
14
|
end
|
@@ -14,8 +14,14 @@ export class DirectUpload {
|
|
14
14
|
|
15
15
|
create(callback) {
|
16
16
|
FileChecksum.create(this.file, (error, checksum) => {
|
17
|
+
if (error) {
|
18
|
+
callback(error)
|
19
|
+
return
|
20
|
+
}
|
21
|
+
|
17
22
|
const blob = new BlobRecord(this.file, checksum, this.url)
|
18
23
|
notify(this.delegate, "directUploadWillCreateBlobWithXHR", blob.xhr)
|
24
|
+
|
19
25
|
blob.create(error => {
|
20
26
|
if (error) {
|
21
27
|
callback(error)
|
@@ -14,17 +14,25 @@
|
|
14
14
|
# update a blob's metadata on a subsequent pass, but you should not update the key or change the uploaded file.
|
15
15
|
# If you need to create a derivative or otherwise change the blob, simply create a new blob and purge the old one.
|
16
16
|
class ActiveStorage::Blob < ActiveRecord::Base
|
17
|
-
|
17
|
+
require_dependency "active_storage/blob/analyzable"
|
18
|
+
require_dependency "active_storage/blob/identifiable"
|
19
|
+
require_dependency "active_storage/blob/representable"
|
20
|
+
|
21
|
+
include Analyzable
|
22
|
+
include Identifiable
|
23
|
+
include Representable
|
18
24
|
|
19
25
|
self.table_name = "active_storage_blobs"
|
20
26
|
|
21
27
|
has_secure_token :key
|
22
|
-
store :metadata, accessors: [ :analyzed, :identified ], coder: JSON
|
28
|
+
store :metadata, accessors: [ :analyzed, :identified ], coder: ActiveRecord::Coders::JSON
|
23
29
|
|
24
30
|
class_attribute :service
|
25
31
|
|
26
32
|
has_many :attachments
|
27
33
|
|
34
|
+
scope :unattached, -> { left_joins(:attachments).where(ActiveStorage::Attachment.table_name => { blob_id: nil }) }
|
35
|
+
|
28
36
|
class << self
|
29
37
|
# You can used the signed ID of a blob to refer to it on the client side without fear of tampering.
|
30
38
|
# This is particularly helpful for direct uploads where the client-side needs to refer to the blob
|
@@ -109,8 +117,11 @@ class ActiveStorage::Blob < ActiveRecord::Base
|
|
109
117
|
# with users. Instead, the +service_url+ should only be exposed as a redirect from a stable, possibly authenticated URL.
|
110
118
|
# Hiding the +service_url+ behind a redirect also gives you the power to change services without updating all URLs. And
|
111
119
|
# it allows permanent URLs that redirect to the +service_url+ to be cached in the view.
|
112
|
-
def service_url(expires_in: service.url_expires_in, disposition: :inline, filename:
|
113
|
-
|
120
|
+
def service_url(expires_in: service.url_expires_in, disposition: :inline, filename: nil, **options)
|
121
|
+
filename = ActiveStorage::Filename.wrap(filename || self.filename)
|
122
|
+
|
123
|
+
service.url key, expires_in: expires_in, filename: filename, content_type: content_type,
|
124
|
+
disposition: forcibly_serve_as_binary? ? :attachment : disposition, **options
|
114
125
|
end
|
115
126
|
|
116
127
|
# Returns a URL that can be used to directly upload a file for this blob on the service. This URL is intended to be
|
@@ -191,4 +202,6 @@ class ActiveStorage::Blob < ActiveRecord::Base
|
|
191
202
|
def forcibly_serve_as_binary?
|
192
203
|
ActiveStorage.content_types_to_serve_as_binary.include?(content_type)
|
193
204
|
end
|
205
|
+
|
206
|
+
ActiveSupport.run_load_hooks(:active_storage_blob, self)
|
194
207
|
end
|
@@ -2,10 +2,19 @@
|
|
2
2
|
|
3
3
|
module ActiveStorage::Blob::Identifiable
|
4
4
|
def identify
|
5
|
-
|
5
|
+
update! content_type: identify_content_type, identified: true unless identified?
|
6
6
|
end
|
7
7
|
|
8
8
|
def identified?
|
9
9
|
identified
|
10
10
|
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def identify_content_type
|
14
|
+
Marcel::MimeType.for download_identifiable_chunk, name: filename.to_s, declared_type: content_type
|
15
|
+
end
|
16
|
+
|
17
|
+
def download_identifiable_chunk
|
18
|
+
service.download_chunk key, 0...4.kilobytes
|
19
|
+
end
|
11
20
|
end
|
@@ -27,7 +27,7 @@ module ActiveStorage::Blob::Representable
|
|
27
27
|
# variable, call ActiveStorage::Blob#variable?.
|
28
28
|
def variant(transformations)
|
29
29
|
if variable?
|
30
|
-
ActiveStorage::Variant.new(self,
|
30
|
+
ActiveStorage::Variant.new(self, transformations)
|
31
31
|
else
|
32
32
|
raise ActiveStorage::InvariableError
|
33
33
|
end
|
@@ -55,7 +55,7 @@ module ActiveStorage::Blob::Representable
|
|
55
55
|
# whether a blob is accepted by any previewer, call ActiveStorage::Blob#previewable?.
|
56
56
|
def preview(transformations)
|
57
57
|
if previewable?
|
58
|
-
ActiveStorage::Preview.new(self,
|
58
|
+
ActiveStorage::Preview.new(self, transformations)
|
59
59
|
else
|
60
60
|
raise ActiveStorage::UnpreviewableError
|
61
61
|
end
|
@@ -3,8 +3,18 @@
|
|
3
3
|
# Encapsulates a string representing a filename to provide convenient access to parts of it and sanitization.
|
4
4
|
# A Filename instance is returned by ActiveStorage::Blob#filename, and is comparable so it can be used for sorting.
|
5
5
|
class ActiveStorage::Filename
|
6
|
+
require_dependency "active_storage/filename/parameters"
|
7
|
+
|
6
8
|
include Comparable
|
7
9
|
|
10
|
+
class << self
|
11
|
+
# Returns a Filename instance based on the given filename. If the filename is a Filename, it is
|
12
|
+
# returned unmodified. If it is a String, it is passed to ActiveStorage::Filename.new.
|
13
|
+
def wrap(filename)
|
14
|
+
filename.kind_of?(self) ? filename : new(filename)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
8
18
|
def initialize(filename)
|
9
19
|
@filename = filename
|
10
20
|
end
|
@@ -21,10 +21,9 @@
|
|
21
21
|
#
|
22
22
|
# Outside of a Rails application, modify +ActiveStorage.previewers+ instead.
|
23
23
|
#
|
24
|
-
# The built-in previewers rely on third-party system libraries
|
25
|
-
#
|
26
|
-
#
|
27
|
-
# * {mupdf}[https://mupdf.com]
|
24
|
+
# The built-in previewers rely on third-party system libraries. Specifically, the built-in video previewer requires
|
25
|
+
# {ffmpeg}[https://www.ffmpeg.org]. Two PDF previewers are provided: one requires {Poppler}[https://poppler.freedesktop.org],
|
26
|
+
# and the other requires {mupdf}[https://mupdf.com] (version 1.8 or newer). To preview PDFs, install either Poppler or mupdf.
|
28
27
|
#
|
29
28
|
# These libraries are not provided by Rails. You must install them yourself to use the built-in previewers. Before you
|
30
29
|
# install and use third-party software, make sure you understand the licensing implications of doing so.
|
@@ -115,7 +115,7 @@ class ActiveStorage::Variant
|
|
115
115
|
|
116
116
|
def download_image
|
117
117
|
require "mini_magick"
|
118
|
-
MiniMagick::Image.create { |file| download_blob_to(file) }
|
118
|
+
MiniMagick::Image.create(blob.filename.extension_with_delimiter) { |file| download_blob_to(file) }
|
119
119
|
end
|
120
120
|
|
121
121
|
def transform(image)
|
@@ -8,6 +8,14 @@
|
|
8
8
|
#
|
9
9
|
# ActiveStorage::Variation.new(resize: "100x100", monochrome: true, trim: true, rotate: "-90")
|
10
10
|
#
|
11
|
+
# You can also combine multiple transformations in one step, e.g. for center-weighted cropping:
|
12
|
+
#
|
13
|
+
# ActiveStorage::Variation.new(combine_options: {
|
14
|
+
# resize: "100x100^",
|
15
|
+
# gravity: "center",
|
16
|
+
# crop: "100x100+0+0",
|
17
|
+
# })
|
18
|
+
#
|
11
19
|
# A list of all possible transformations is available at https://www.imagemagick.org/script/mogrify.php.
|
12
20
|
class ActiveStorage::Variation
|
13
21
|
attr_reader :transformations
|
data/config/routes.rb
CHANGED
@@ -11,30 +11,18 @@ Rails.application.routes.draw do
|
|
11
11
|
resolve("ActiveStorage::Attachment") { |attachment, options| route_for(:rails_blob, attachment.blob, options) }
|
12
12
|
|
13
13
|
|
14
|
-
get "/rails/active_storage/
|
14
|
+
get "/rails/active_storage/representations/:signed_blob_id/:variation_key/*filename" => "active_storage/representations#show", as: :rails_blob_representation
|
15
15
|
|
16
|
-
direct :
|
17
|
-
signed_blob_id =
|
18
|
-
variation_key =
|
19
|
-
filename =
|
16
|
+
direct :rails_representation do |representation, options|
|
17
|
+
signed_blob_id = representation.blob.signed_id
|
18
|
+
variation_key = representation.variation.key
|
19
|
+
filename = representation.blob.filename
|
20
20
|
|
21
|
-
route_for(:
|
21
|
+
route_for(:rails_blob_representation, signed_blob_id, variation_key, filename, options)
|
22
22
|
end
|
23
23
|
|
24
|
-
resolve("ActiveStorage::Variant") { |variant, options| route_for(:
|
25
|
-
|
26
|
-
|
27
|
-
get "/rails/active_storage/previews/:signed_blob_id/:variation_key/*filename" => "active_storage/previews#show", as: :rails_blob_preview
|
28
|
-
|
29
|
-
direct :rails_preview do |preview, options|
|
30
|
-
signed_blob_id = preview.blob.signed_id
|
31
|
-
variation_key = preview.variation.key
|
32
|
-
filename = preview.blob.filename
|
33
|
-
|
34
|
-
route_for(:rails_blob_preview, signed_blob_id, variation_key, filename, options)
|
35
|
-
end
|
36
|
-
|
37
|
-
resolve("ActiveStorage::Preview") { |preview, options| route_for(:rails_preview, preview, options) }
|
24
|
+
resolve("ActiveStorage::Variant") { |variant, options| route_for(:rails_representation, variant, options) }
|
25
|
+
resolve("ActiveStorage::Preview") { |preview, options| route_for(:rails_representation, preview, options) }
|
38
26
|
|
39
27
|
|
40
28
|
get "/rails/active_storage/disk/:encoded_key/*filename" => "active_storage/disk#show", as: :rails_disk_service
|
@@ -3,6 +3,8 @@
|
|
3
3
|
module ActiveStorage
|
4
4
|
# Extracts width and height in pixels from an image blob.
|
5
5
|
#
|
6
|
+
# If the image contains EXIF data indicating its angle is 90 or 270 degrees, its width and height are swapped for convenience.
|
7
|
+
#
|
6
8
|
# Example:
|
7
9
|
#
|
8
10
|
# ActiveStorage::Analyzer::ImageAnalyzer.new(blob).metadata
|
@@ -17,7 +19,11 @@ module ActiveStorage
|
|
17
19
|
|
18
20
|
def metadata
|
19
21
|
read_image do |image|
|
20
|
-
|
22
|
+
if rotated_image?(image)
|
23
|
+
{ width: image.height, height: image.width }
|
24
|
+
else
|
25
|
+
{ width: image.width, height: image.height }
|
26
|
+
end
|
21
27
|
end
|
22
28
|
rescue LoadError
|
23
29
|
logger.info "Skipping image analysis because the mini_magick gem isn't installed"
|
@@ -31,5 +37,9 @@ module ActiveStorage
|
|
31
37
|
yield MiniMagick::Image.new(file.path)
|
32
38
|
end
|
33
39
|
end
|
40
|
+
|
41
|
+
def rotated_image?(image)
|
42
|
+
%w[ RightTop LeftBottom ].include?(image["%[orientation]"])
|
43
|
+
end
|
34
44
|
end
|
35
45
|
end
|
@@ -38,13 +38,15 @@ module ActiveStorage
|
|
38
38
|
end
|
39
39
|
CODE
|
40
40
|
|
41
|
-
has_one :"#{name}_attachment", -> { where(name: name) }, class_name: "ActiveStorage::Attachment", as: :record, inverse_of: :record
|
41
|
+
has_one :"#{name}_attachment", -> { where(name: name) }, class_name: "ActiveStorage::Attachment", as: :record, inverse_of: :record, dependent: false
|
42
42
|
has_one :"#{name}_blob", through: :"#{name}_attachment", class_name: "ActiveStorage::Blob", source: :blob
|
43
43
|
|
44
44
|
scope :"with_attached_#{name}", -> { includes("#{name}_attachment": :blob) }
|
45
45
|
|
46
46
|
if dependent == :purge_later
|
47
47
|
after_destroy_commit { public_send(name).purge_later }
|
48
|
+
else
|
49
|
+
before_destroy { public_send(name).detach }
|
48
50
|
end
|
49
51
|
end
|
50
52
|
|
@@ -83,13 +85,25 @@ module ActiveStorage
|
|
83
85
|
end
|
84
86
|
CODE
|
85
87
|
|
86
|
-
has_many :"#{name}_attachments", -> { where(name: name) }, as: :record, class_name: "ActiveStorage::Attachment", inverse_of: :record
|
88
|
+
has_many :"#{name}_attachments", -> { where(name: name) }, as: :record, class_name: "ActiveStorage::Attachment", inverse_of: :record, dependent: false do
|
89
|
+
def purge
|
90
|
+
each(&:purge)
|
91
|
+
reset
|
92
|
+
end
|
93
|
+
|
94
|
+
def purge_later
|
95
|
+
each(&:purge_later)
|
96
|
+
reset
|
97
|
+
end
|
98
|
+
end
|
87
99
|
has_many :"#{name}_blobs", through: :"#{name}_attachments", class_name: "ActiveStorage::Blob", source: :blob
|
88
100
|
|
89
101
|
scope :"with_attached_#{name}", -> { includes("#{name}_attachments": :blob) }
|
90
102
|
|
91
103
|
if dependent == :purge_later
|
92
104
|
after_destroy_commit { public_send(name).purge_later }
|
105
|
+
else
|
106
|
+
before_destroy { public_send(name).detach }
|
93
107
|
end
|
94
108
|
end
|
95
109
|
end
|
@@ -44,20 +44,16 @@ module ActiveStorage
|
|
44
44
|
attachments.destroy_all if attached?
|
45
45
|
end
|
46
46
|
|
47
|
+
##
|
48
|
+
# :method: purge
|
49
|
+
#
|
47
50
|
# Directly purges each associated attachment (i.e. destroys the blobs and
|
48
51
|
# attachments and deletes the files on the service).
|
49
|
-
def purge
|
50
|
-
if attached?
|
51
|
-
attachments.each(&:purge)
|
52
|
-
attachments.reload
|
53
|
-
end
|
54
|
-
end
|
55
52
|
|
53
|
+
|
54
|
+
##
|
55
|
+
# :method: purge_later
|
56
|
+
#
|
56
57
|
# Purges each associated attachment through the queuing system.
|
57
|
-
def purge_later
|
58
|
-
if attached?
|
59
|
-
attachments.each(&:purge_later)
|
60
|
-
end
|
61
|
-
end
|
62
58
|
end
|
63
59
|
end
|
@@ -20,10 +20,16 @@ module ActiveStorage
|
|
20
20
|
# person.avatar.attach(io: File.open("/path/to/face.jpg"), filename: "face.jpg", content_type: "image/jpg")
|
21
21
|
# person.avatar.attach(avatar_blob) # ActiveStorage::Blob object
|
22
22
|
def attach(attachable)
|
23
|
-
if attached?
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
blob_was = blob if attached?
|
24
|
+
blob = create_blob_from(attachable)
|
25
|
+
|
26
|
+
unless blob == blob_was
|
27
|
+
transaction do
|
28
|
+
detach
|
29
|
+
write_attachment build_attachment(blob: blob)
|
30
|
+
end
|
31
|
+
|
32
|
+
blob_was.purge_later if blob_was && dependent == :purge_later
|
27
33
|
end
|
28
34
|
end
|
29
35
|
|
@@ -63,17 +69,10 @@ module ActiveStorage
|
|
63
69
|
end
|
64
70
|
|
65
71
|
private
|
66
|
-
|
67
|
-
blob.tap do
|
68
|
-
transaction do
|
69
|
-
detach
|
70
|
-
write_attachment build_attachment_from(attachable)
|
71
|
-
end
|
72
|
-
end.purge_later
|
73
|
-
end
|
72
|
+
delegate :transaction, to: :record
|
74
73
|
|
75
|
-
def
|
76
|
-
ActiveStorage::Attachment.new(record: record, name: name, blob:
|
74
|
+
def build_attachment(blob:)
|
75
|
+
ActiveStorage::Attachment.new(record: record, name: name, blob: blob)
|
77
76
|
end
|
78
77
|
|
79
78
|
def write_attachment(attachment)
|
@@ -3,7 +3,8 @@
|
|
3
3
|
require "rails"
|
4
4
|
require "active_storage"
|
5
5
|
|
6
|
-
require "active_storage/previewer/
|
6
|
+
require "active_storage/previewer/poppler_pdf_previewer"
|
7
|
+
require "active_storage/previewer/mupdf_previewer"
|
7
8
|
require "active_storage/previewer/video_previewer"
|
8
9
|
|
9
10
|
require "active_storage/analyzer/image_analyzer"
|
@@ -14,11 +15,19 @@ module ActiveStorage
|
|
14
15
|
isolate_namespace ActiveStorage
|
15
16
|
|
16
17
|
config.active_storage = ActiveSupport::OrderedOptions.new
|
17
|
-
config.active_storage.previewers = [ ActiveStorage::Previewer::
|
18
|
+
config.active_storage.previewers = [ ActiveStorage::Previewer::PopplerPDFPreviewer, ActiveStorage::Previewer::MuPDFPreviewer, ActiveStorage::Previewer::VideoPreviewer ]
|
18
19
|
config.active_storage.analyzers = [ ActiveStorage::Analyzer::ImageAnalyzer, ActiveStorage::Analyzer::VideoAnalyzer ]
|
19
20
|
config.active_storage.paths = ActiveSupport::OrderedOptions.new
|
20
21
|
|
21
|
-
config.active_storage.variable_content_types = %w(
|
22
|
+
config.active_storage.variable_content_types = %w(
|
23
|
+
image/png
|
24
|
+
image/gif
|
25
|
+
image/jpg
|
26
|
+
image/jpeg
|
27
|
+
image/vnd.adobe.photoshop
|
28
|
+
image/vnd.microsoft.icon
|
29
|
+
)
|
30
|
+
|
22
31
|
config.active_storage.content_types_to_serve_as_binary = %w(
|
23
32
|
text/html
|
24
33
|
text/javascript
|
@@ -60,7 +69,7 @@ module ActiveStorage
|
|
60
69
|
end
|
61
70
|
|
62
71
|
initializer "active_storage.services" do
|
63
|
-
|
72
|
+
ActiveSupport.on_load(:active_storage_blob) do
|
64
73
|
if config_choice = Rails.configuration.active_storage.service
|
65
74
|
configs = Rails.configuration.active_storage.service_configurations ||= begin
|
66
75
|
config_file = Pathname.new(Rails.root.join("config/storage.yml"))
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveStorage
|
4
|
+
class Previewer::MuPDFPreviewer < Previewer
|
5
|
+
class << self
|
6
|
+
def accept?(blob)
|
7
|
+
blob.content_type == "application/pdf" && mutool_exists?
|
8
|
+
end
|
9
|
+
|
10
|
+
def mutool_path
|
11
|
+
ActiveStorage.paths[:mutool] || "mutool"
|
12
|
+
end
|
13
|
+
|
14
|
+
def mutool_exists?
|
15
|
+
return @mutool_exists unless @mutool_exists.nil?
|
16
|
+
|
17
|
+
system mutool_path, out: File::NULL, err: File::NULL
|
18
|
+
|
19
|
+
@mutool_exists = $?.exitstatus == 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def preview
|
24
|
+
download_blob_to_tempfile do |input|
|
25
|
+
draw_first_page_from input do |output|
|
26
|
+
yield io: output, filename: "#{blob.filename.base}.png", content_type: "image/png"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def draw_first_page_from(file, &block)
|
33
|
+
draw self.class.mutool_path, "draw", "-F", "png", "-o", "-", file.path, "1", &block
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveStorage
|
4
|
+
class Previewer::PopplerPDFPreviewer < Previewer
|
5
|
+
class << self
|
6
|
+
def accept?(blob)
|
7
|
+
blob.content_type == "application/pdf" && pdftoppm_exists?
|
8
|
+
end
|
9
|
+
|
10
|
+
def pdftoppm_path
|
11
|
+
ActiveStorage.paths[:pdftoppm] || "pdftoppm"
|
12
|
+
end
|
13
|
+
|
14
|
+
def pdftoppm_exists?
|
15
|
+
return @pdftoppm_exists unless @pdftoppm_exists.nil?
|
16
|
+
|
17
|
+
@pdftoppm_exists = system(pdftoppm_path, "-v", out: File::NULL, err: File::NULL)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def preview
|
22
|
+
download_blob_to_tempfile do |input|
|
23
|
+
draw_first_page_from input do |output|
|
24
|
+
yield io: output, filename: "#{blob.filename.base}.png", content_type: "image/png"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def draw_first_page_from(file, &block)
|
31
|
+
# use 72 dpi to match thumbnail dimesions of the PDF
|
32
|
+
draw self.class.pdftoppm_path, "-singlefile", "-r", "72", "-png", file.path, &block
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -73,6 +73,11 @@ module ActiveStorage
|
|
73
73
|
raise NotImplementedError
|
74
74
|
end
|
75
75
|
|
76
|
+
# Return the partial content in the byte +range+ of the file at the +key+.
|
77
|
+
def download_chunk(key, range)
|
78
|
+
raise NotImplementedError
|
79
|
+
end
|
80
|
+
|
76
81
|
# Delete the file at the +key+.
|
77
82
|
def delete(key)
|
78
83
|
raise NotImplementedError
|
@@ -8,14 +8,13 @@ module ActiveStorage
|
|
8
8
|
# Wraps the Microsoft Azure Storage Blob Service as an Active Storage service.
|
9
9
|
# See ActiveStorage::Service for the generic API documentation that applies to all services.
|
10
10
|
class Service::AzureStorageService < Service
|
11
|
-
attr_reader :client, :
|
11
|
+
attr_reader :client, :blobs, :container, :signer
|
12
12
|
|
13
|
-
def initialize(
|
13
|
+
def initialize(storage_account_name:, storage_access_key:, container:)
|
14
14
|
@client = Azure::Storage::Client.create(storage_account_name: storage_account_name, storage_access_key: storage_access_key)
|
15
15
|
@signer = Azure::Storage::Core::Auth::SharedAccessSignature.new(storage_account_name, storage_access_key)
|
16
16
|
@blobs = client.blob_client
|
17
17
|
@container = container
|
18
|
-
@path = path
|
19
18
|
end
|
20
19
|
|
21
20
|
def upload(key, io, checksum: nil)
|
@@ -41,6 +40,13 @@ module ActiveStorage
|
|
41
40
|
end
|
42
41
|
end
|
43
42
|
|
43
|
+
def download_chunk(key, range)
|
44
|
+
instrument :download_chunk, key: key, range: range do
|
45
|
+
_, io = blobs.get_blob(container, key, start_range: range.begin, end_range: range.exclude_end? ? range.end - 1 : range.end)
|
46
|
+
io.force_encoding(Encoding::BINARY)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
44
50
|
def delete(key)
|
45
51
|
instrument :delete, key: key do
|
46
52
|
begin
|
@@ -77,9 +83,9 @@ module ActiveStorage
|
|
77
83
|
|
78
84
|
def url(key, expires_in:, filename:, disposition:, content_type:)
|
79
85
|
instrument :url, key: key do |payload|
|
80
|
-
base_url = url_for(key)
|
81
86
|
generated_url = signer.signed_uri(
|
82
|
-
|
87
|
+
uri_for(key), false,
|
88
|
+
service: "b",
|
83
89
|
permissions: "r",
|
84
90
|
expiry: format_expiry(expires_in),
|
85
91
|
content_disposition: content_disposition_with(type: disposition, filename: filename),
|
@@ -94,9 +100,12 @@ module ActiveStorage
|
|
94
100
|
|
95
101
|
def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:)
|
96
102
|
instrument :url, key: key do |payload|
|
97
|
-
|
98
|
-
|
99
|
-
|
103
|
+
generated_url = signer.signed_uri(
|
104
|
+
uri_for(key), false,
|
105
|
+
service: "b",
|
106
|
+
permissions: "rw",
|
107
|
+
expiry: format_expiry(expires_in)
|
108
|
+
).to_s
|
100
109
|
|
101
110
|
payload[:url] = generated_url
|
102
111
|
|
@@ -109,8 +118,8 @@ module ActiveStorage
|
|
109
118
|
end
|
110
119
|
|
111
120
|
private
|
112
|
-
def
|
113
|
-
"#{
|
121
|
+
def uri_for(key)
|
122
|
+
blobs.generate_uri("#{container}/#{key}")
|
114
123
|
end
|
115
124
|
|
116
125
|
def blob_for(key)
|
@@ -9,10 +9,10 @@ module ActiveStorage
|
|
9
9
|
# Wraps a local disk path as an Active Storage service. See ActiveStorage::Service for the generic API
|
10
10
|
# documentation that applies to all services.
|
11
11
|
class Service::DiskService < Service
|
12
|
-
attr_reader :root
|
12
|
+
attr_reader :root
|
13
13
|
|
14
|
-
def initialize(root
|
15
|
-
@root
|
14
|
+
def initialize(root:)
|
15
|
+
@root = root
|
16
16
|
end
|
17
17
|
|
18
18
|
def upload(key, io, checksum: nil)
|
@@ -38,6 +38,15 @@ module ActiveStorage
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
+
def download_chunk(key, range)
|
42
|
+
instrument :download_chunk, key: key, range: range do
|
43
|
+
File.open(path_for(key), "rb") do |file|
|
44
|
+
file.seek range.begin
|
45
|
+
file.read range.size
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
41
50
|
def delete(key)
|
42
51
|
instrument :delete, key: key do
|
43
52
|
begin
|
@@ -69,12 +78,11 @@ module ActiveStorage
|
|
69
78
|
verified_key_with_expiration = ActiveStorage.verifier.generate(key, expires_in: expires_in, purpose: :blob_key)
|
70
79
|
|
71
80
|
generated_url =
|
72
|
-
|
81
|
+
url_helpers.rails_disk_service_path(
|
73
82
|
verified_key_with_expiration,
|
74
83
|
filename: filename,
|
75
84
|
disposition: content_disposition_with(type: disposition, filename: filename),
|
76
|
-
content_type: content_type
|
77
|
-
host: host
|
85
|
+
content_type: content_type
|
78
86
|
)
|
79
87
|
|
80
88
|
payload[:url] = generated_url
|
@@ -96,7 +104,7 @@ module ActiveStorage
|
|
96
104
|
purpose: :blob_token }
|
97
105
|
)
|
98
106
|
|
99
|
-
generated_url =
|
107
|
+
generated_url = url_helpers.update_rails_disk_service_path(verified_token_with_expiration)
|
100
108
|
|
101
109
|
payload[:url] = generated_url
|
102
110
|
|
@@ -121,11 +129,17 @@ module ActiveStorage
|
|
121
129
|
path_for(key).tap { |path| FileUtils.mkdir_p File.dirname(path) }
|
122
130
|
end
|
123
131
|
|
132
|
+
|
124
133
|
def ensure_integrity_of(key, checksum)
|
125
134
|
unless Digest::MD5.file(path_for(key)).base64digest == checksum
|
126
135
|
delete key
|
127
136
|
raise ActiveStorage::IntegrityError
|
128
137
|
end
|
129
138
|
end
|
139
|
+
|
140
|
+
|
141
|
+
def url_helpers
|
142
|
+
@url_helpers ||= Rails.application.routes.url_helpers
|
143
|
+
end
|
130
144
|
end
|
131
145
|
end
|
@@ -3,7 +3,10 @@
|
|
3
3
|
gem "google-cloud-storage", "~> 1.8"
|
4
4
|
|
5
5
|
require "google/cloud/storage"
|
6
|
+
require "net/http"
|
7
|
+
|
6
8
|
require "active_support/core_ext/object/to_query"
|
9
|
+
require "active_storage/filename"
|
7
10
|
|
8
11
|
module ActiveStorage
|
9
12
|
# Wraps the Google Cloud Storage as an Active Storage service. See ActiveStorage::Service for the generic API
|
@@ -43,6 +46,16 @@ module ActiveStorage
|
|
43
46
|
end
|
44
47
|
end
|
45
48
|
|
49
|
+
def download_chunk(key, range)
|
50
|
+
instrument :download_chunk, key: key, range: range do
|
51
|
+
uri = URI(url(key, expires_in: 30.seconds, filename: ActiveStorage::Filename.new(""), content_type: "application/octet-stream", disposition: "inline"))
|
52
|
+
|
53
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |client|
|
54
|
+
client.get(uri, "Range" => "bytes=#{range.begin}-#{range.exclude_end? ? range.end - 1 : range.end}").body
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
46
59
|
def delete(key)
|
47
60
|
instrument :delete, key: key do
|
48
61
|
begin
|
@@ -80,10 +93,9 @@ module ActiveStorage
|
|
80
93
|
end
|
81
94
|
end
|
82
95
|
|
83
|
-
def url_for_direct_upload(key, expires_in:,
|
96
|
+
def url_for_direct_upload(key, expires_in:, checksum:, **)
|
84
97
|
instrument :url, key: key do |payload|
|
85
|
-
generated_url = bucket.signed_url key, method: "PUT", expires: expires_in,
|
86
|
-
content_type: content_type, content_md5: checksum
|
98
|
+
generated_url = bucket.signed_url key, method: "PUT", expires: expires_in, content_md5: checksum
|
87
99
|
|
88
100
|
payload[:url] = generated_url
|
89
101
|
|
@@ -91,8 +103,8 @@ module ActiveStorage
|
|
91
103
|
end
|
92
104
|
end
|
93
105
|
|
94
|
-
def headers_for_direct_upload(key,
|
95
|
-
{ "Content-
|
106
|
+
def headers_for_direct_upload(key, checksum:, **)
|
107
|
+
{ "Content-MD5" => checksum }
|
96
108
|
end
|
97
109
|
|
98
110
|
private
|
@@ -9,7 +9,7 @@ module ActiveStorage
|
|
9
9
|
class Service::MirrorService < Service
|
10
10
|
attr_reader :primary, :mirrors
|
11
11
|
|
12
|
-
delegate :download, :exist?, :url, to: :primary
|
12
|
+
delegate :download, :download_chunk, :exist?, :url, to: :primary
|
13
13
|
|
14
14
|
# Stitch together from named services.
|
15
15
|
def self.build(primary:, mirrors:, configurator:, **options) #:nodoc:
|
@@ -9,8 +9,8 @@ module ActiveStorage
|
|
9
9
|
class Service::S3Service < Service
|
10
10
|
attr_reader :client, :bucket, :upload_options
|
11
11
|
|
12
|
-
def initialize(
|
13
|
-
@client = Aws::S3::Resource.new(
|
12
|
+
def initialize(bucket:, upload: {}, **options)
|
13
|
+
@client = Aws::S3::Resource.new(**options)
|
14
14
|
@bucket = @client.bucket(bucket)
|
15
15
|
|
16
16
|
@upload_options = upload
|
@@ -38,6 +38,12 @@ module ActiveStorage
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
+
def download_chunk(key, range)
|
42
|
+
instrument :download_chunk, key: key, range: range do
|
43
|
+
object_for(key).get(range: "bytes=#{range.begin}-#{range.exclude_end? ? range.end - 1 : range.end}").body.read.force_encoding(Encoding::BINARY)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
41
47
|
def delete(key)
|
42
48
|
instrument :delete, key: key do
|
43
49
|
object_for(key).delete
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activestorage
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.2.0.
|
4
|
+
version: 5.2.0.rc2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-03-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 5.2.0.
|
19
|
+
version: 5.2.0.rc2
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 5.2.0.
|
26
|
+
version: 5.2.0.rc2
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activerecord
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 5.2.0.
|
33
|
+
version: 5.2.0.rc2
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 5.2.0.
|
40
|
+
version: 5.2.0.rc2
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: marcel
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,20 +52,6 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 0.3.1
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: webmock
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: 3.2.1
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: 3.2.1
|
69
55
|
description: Attach cloud and local files in Rails applications.
|
70
56
|
email: david@loudthinking.com
|
71
57
|
executables: []
|
@@ -79,8 +65,7 @@ files:
|
|
79
65
|
- app/controllers/active_storage/blobs_controller.rb
|
80
66
|
- app/controllers/active_storage/direct_uploads_controller.rb
|
81
67
|
- app/controllers/active_storage/disk_controller.rb
|
82
|
-
- app/controllers/active_storage/
|
83
|
-
- app/controllers/active_storage/variants_controller.rb
|
68
|
+
- app/controllers/active_storage/representations_controller.rb
|
84
69
|
- app/controllers/concerns/active_storage/set_blob.rb
|
85
70
|
- app/javascript/activestorage/blob_record.js
|
86
71
|
- app/javascript/activestorage/blob_upload.js
|
@@ -101,7 +86,6 @@ files:
|
|
101
86
|
- app/models/active_storage/blob/representable.rb
|
102
87
|
- app/models/active_storage/filename.rb
|
103
88
|
- app/models/active_storage/filename/parameters.rb
|
104
|
-
- app/models/active_storage/identification.rb
|
105
89
|
- app/models/active_storage/preview.rb
|
106
90
|
- app/models/active_storage/variant.rb
|
107
91
|
- app/models/active_storage/variation.rb
|
@@ -122,7 +106,8 @@ files:
|
|
122
106
|
- lib/active_storage/gem_version.rb
|
123
107
|
- lib/active_storage/log_subscriber.rb
|
124
108
|
- lib/active_storage/previewer.rb
|
125
|
-
- lib/active_storage/previewer/
|
109
|
+
- lib/active_storage/previewer/mupdf_previewer.rb
|
110
|
+
- lib/active_storage/previewer/poppler_pdf_previewer.rb
|
126
111
|
- lib/active_storage/previewer/video_previewer.rb
|
127
112
|
- lib/active_storage/service.rb
|
128
113
|
- lib/active_storage/service/azure_storage_service.rb
|
@@ -137,8 +122,8 @@ homepage: http://rubyonrails.org
|
|
137
122
|
licenses:
|
138
123
|
- MIT
|
139
124
|
metadata:
|
140
|
-
source_code_uri: https://github.com/rails/rails/tree/v5.2.0.
|
141
|
-
changelog_uri: https://github.com/rails/rails/blob/v5.2.0.
|
125
|
+
source_code_uri: https://github.com/rails/rails/tree/v5.2.0.rc2/activestorage
|
126
|
+
changelog_uri: https://github.com/rails/rails/blob/v5.2.0.rc2/activestorage/CHANGELOG.md
|
142
127
|
post_install_message:
|
143
128
|
rdoc_options: []
|
144
129
|
require_paths:
|
@@ -155,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
140
|
version: 1.3.1
|
156
141
|
requirements: []
|
157
142
|
rubyforge_project:
|
158
|
-
rubygems_version: 2.7.
|
143
|
+
rubygems_version: 2.7.6
|
159
144
|
signing_key:
|
160
145
|
specification_version: 4
|
161
146
|
summary: Local and cloud file storage framework.
|
@@ -1,10 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class ActiveStorage::PreviewsController < ActionController::Base
|
4
|
-
include ActiveStorage::SetBlob
|
5
|
-
|
6
|
-
def show
|
7
|
-
expires_in ActiveStorage::Blob.service.url_expires_in
|
8
|
-
redirect_to ActiveStorage::Preview.new(@blob, params[:variation_key]).processed.service_url(disposition: params[:disposition])
|
9
|
-
end
|
10
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class ActiveStorage::Identification
|
4
|
-
attr_reader :blob
|
5
|
-
|
6
|
-
def initialize(blob)
|
7
|
-
@blob = blob
|
8
|
-
end
|
9
|
-
|
10
|
-
def apply
|
11
|
-
blob.update!(content_type: content_type, identified: true) unless blob.identified?
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
def content_type
|
16
|
-
Marcel::MimeType.for(identifiable_chunk, name: filename, declared_type: declared_content_type)
|
17
|
-
end
|
18
|
-
|
19
|
-
|
20
|
-
def identifiable_chunk
|
21
|
-
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |client|
|
22
|
-
client.get(uri, "Range" => "0-4096").body
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def uri
|
27
|
-
@uri ||= URI.parse(blob.service_url)
|
28
|
-
end
|
29
|
-
|
30
|
-
|
31
|
-
def filename
|
32
|
-
blob.filename.to_s
|
33
|
-
end
|
34
|
-
|
35
|
-
def declared_content_type
|
36
|
-
blob.content_type
|
37
|
-
end
|
38
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveStorage
|
4
|
-
class Previewer::PDFPreviewer < Previewer
|
5
|
-
def self.accept?(blob)
|
6
|
-
blob.content_type == "application/pdf"
|
7
|
-
end
|
8
|
-
|
9
|
-
def preview
|
10
|
-
download_blob_to_tempfile do |input|
|
11
|
-
draw_first_page_from input do |output|
|
12
|
-
yield io: output, filename: "#{blob.filename.base}.png", content_type: "image/png"
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
def draw_first_page_from(file, &block)
|
19
|
-
draw mutool_path, "draw", "-F", "png", "-o", "-", file.path, "1", &block
|
20
|
-
end
|
21
|
-
|
22
|
-
def mutool_path
|
23
|
-
ActiveStorage.paths[:mutool] || "mutool"
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|