s3_swf_upload 0.3.2
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.
- data/.gitignore +6 -0
- data/CHANGELOG +26 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +20 -0
- data/Manifest +34 -0
- data/README.textile +223 -0
- data/Rakefile +14 -0
- data/flex_src/bin-release/flex-config.xml +361 -0
- data/flex_src/compile +2 -0
- data/flex_src/src/Globals.as +15 -0
- data/flex_src/src/S3Uploader.as +204 -0
- data/flex_src/src/com/adobe/net/MimeTypeMap.as +196 -0
- data/flex_src/src/com/elctech/S3UploadOptions.as +32 -0
- data/flex_src/src/com/elctech/S3UploadRequest.as +259 -0
- data/flex_src/src/com/nathancolgate/s3_swf_upload/BrowseButton.as +55 -0
- data/flex_src/src/com/nathancolgate/s3_swf_upload/S3Queue.as +117 -0
- data/flex_src/src/com/nathancolgate/s3_swf_upload/S3Signature.as +118 -0
- data/flex_src/src/com/nathancolgate/s3_swf_upload/S3Upload.as +111 -0
- data/lib/patch/integer.rb +12 -0
- data/lib/s3_swf_upload/railtie.rb +16 -0
- data/lib/s3_swf_upload/railties/generators/s3_swf_upload.rb +19 -0
- data/lib/s3_swf_upload/railties/generators/uploader/USAGE +10 -0
- data/lib/s3_swf_upload/railties/generators/uploader/templates/amazon_s3.yml +20 -0
- data/lib/s3_swf_upload/railties/generators/uploader/templates/s3_down_button.gif +0 -0
- data/lib/s3_swf_upload/railties/generators/uploader/templates/s3_over_button.gif +0 -0
- data/lib/s3_swf_upload/railties/generators/uploader/templates/s3_up_button.gif +0 -0
- data/lib/s3_swf_upload/railties/generators/uploader/templates/s3_upload.js +118 -0
- data/lib/s3_swf_upload/railties/generators/uploader/templates/s3_upload.swf +0 -0
- data/lib/s3_swf_upload/railties/generators/uploader/templates/s3_uploads_controller.rb +53 -0
- data/lib/s3_swf_upload/railties/generators/uploader/uploader_generator.rb +20 -0
- data/lib/s3_swf_upload/railties/tasks/crossdomain.xml +5 -0
- data/lib/s3_swf_upload/s3_config.rb +43 -0
- data/lib/s3_swf_upload/signature.rb +203 -0
- data/lib/s3_swf_upload/view_helpers.rb +171 -0
- data/lib/s3_swf_upload.rb +10 -0
- data/s3_swf_upload.gemspec +29 -0
- metadata +103 -0
@@ -0,0 +1,118 @@
|
|
1
|
+
package com.nathancolgate.s3_swf_upload {
|
2
|
+
|
3
|
+
import com.elctech.S3UploadOptions;
|
4
|
+
import com.nathancolgate.s3_swf_upload.*;
|
5
|
+
import flash.external.ExternalInterface;
|
6
|
+
import com.adobe.net.MimeTypeMap;
|
7
|
+
|
8
|
+
import flash.net.*
|
9
|
+
import flash.events.*
|
10
|
+
|
11
|
+
public class S3Signature {
|
12
|
+
|
13
|
+
private var upload_options:S3UploadOptions;
|
14
|
+
private var _file:FileReference;
|
15
|
+
//private var _prefixPath:String
|
16
|
+
|
17
|
+
public var s3upload:S3Upload;
|
18
|
+
|
19
|
+
public function S3Signature(file:FileReference,
|
20
|
+
signatureUrl:String,
|
21
|
+
prefixPath:String) {
|
22
|
+
_file = file;
|
23
|
+
// _prefixPath = prefixPath
|
24
|
+
// Create options list for file s3 upload metadata
|
25
|
+
upload_options = new S3UploadOptions;
|
26
|
+
upload_options.FileSize = _file.size.toString();
|
27
|
+
upload_options.FileName = getFileName(_file);
|
28
|
+
upload_options.ContentType = getContentType(upload_options.FileName);
|
29
|
+
upload_options.key = prefixPath + upload_options.FileName;
|
30
|
+
|
31
|
+
var variables:URLVariables = new URLVariables();
|
32
|
+
variables.key = upload_options.key
|
33
|
+
variables.content_type = upload_options.ContentType;
|
34
|
+
|
35
|
+
var request:URLRequest = new URLRequest(signatureUrl);
|
36
|
+
request.method = URLRequestMethod.GET;
|
37
|
+
request.data = variables;
|
38
|
+
|
39
|
+
var signature:URLLoader = new URLLoader();
|
40
|
+
signature.dataFormat = URLLoaderDataFormat.TEXT;
|
41
|
+
signature.addEventListener(Event.OPEN, openHandler);
|
42
|
+
signature.addEventListener(ProgressEvent.PROGRESS, progressHandler);
|
43
|
+
signature.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
|
44
|
+
signature.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
|
45
|
+
signature.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
|
46
|
+
signature.addEventListener(Event.COMPLETE, completeHandler);
|
47
|
+
signature.load(request);
|
48
|
+
}
|
49
|
+
|
50
|
+
private function openHandler(event:Event):void {
|
51
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onSignatureOpen',toJavascript(_file),event);
|
52
|
+
}
|
53
|
+
|
54
|
+
private function progressHandler(progress_event:ProgressEvent):void {
|
55
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onSignatureProgress',toJavascript(_file),progress_event);
|
56
|
+
}
|
57
|
+
|
58
|
+
private function securityErrorHandler(security_error_event:SecurityErrorEvent):void {
|
59
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onSignatureSecurityError',toJavascript(_file),security_error_event);
|
60
|
+
}
|
61
|
+
|
62
|
+
private function httpStatusHandler(http_status_event:HTTPStatusEvent):void {
|
63
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onSignatureHttpStatus',toJavascript(_file),http_status_event);
|
64
|
+
}
|
65
|
+
|
66
|
+
private function ioErrorHandler(io_error_event:IOErrorEvent):void {
|
67
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onSignatureIOError',toJavascript(_file),io_error_event);
|
68
|
+
}
|
69
|
+
|
70
|
+
private function completeHandler(event:Event):void {
|
71
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onSignatureComplete',toJavascript(_file),event);
|
72
|
+
var loader:URLLoader = URLLoader(event.target);
|
73
|
+
var xml:XML = new XML(loader.data);
|
74
|
+
|
75
|
+
// create the s3 options object
|
76
|
+
upload_options.policy = xml.policy;
|
77
|
+
upload_options.signature = xml.signature;
|
78
|
+
upload_options.bucket = xml.bucket;
|
79
|
+
upload_options.AWSAccessKeyId = xml.accesskeyid;
|
80
|
+
upload_options.acl = xml.acl;
|
81
|
+
upload_options.Expires = xml.expirationdate;
|
82
|
+
upload_options.Secure = xml.https;
|
83
|
+
upload_options.newKey = xml.newKey; //NOTE that we stop caring about the specified prefix if we have a newkey.
|
84
|
+
|
85
|
+
if (xml.errorMessage != "") {
|
86
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onSignatureXMLError',toJavascript(_file),xml.errorMessage);
|
87
|
+
return;
|
88
|
+
}
|
89
|
+
|
90
|
+
s3upload = new S3Upload(upload_options);
|
91
|
+
}
|
92
|
+
|
93
|
+
/* MISC */
|
94
|
+
|
95
|
+
private function getContentType(fileName:String):String {
|
96
|
+
var fileNameArray:Array = fileName.split(/\./);
|
97
|
+
var fileExtension:String = fileNameArray[fileNameArray.length - 1];
|
98
|
+
var mimeMap:MimeTypeMap = new MimeTypeMap;
|
99
|
+
var contentType:String = mimeMap.getMimeType(fileExtension);
|
100
|
+
return contentType;
|
101
|
+
}
|
102
|
+
|
103
|
+
private function getFileName(file:FileReference):String {
|
104
|
+
var fileName:String = file.name.replace(/^.*(\\|\/)/gi, '').replace(/[^A-Za-z0-9\.\-]/gi, '_');
|
105
|
+
return fileName;
|
106
|
+
}
|
107
|
+
|
108
|
+
// Turns a FileReference into an Object so that ExternalInterface doesn't choke
|
109
|
+
private function toJavascript(file:FileReference):Object{
|
110
|
+
var javascriptable_file:Object = new Object();
|
111
|
+
javascriptable_file.name = file.name;
|
112
|
+
javascriptable_file.size = file.size;
|
113
|
+
javascriptable_file.type = file.type;
|
114
|
+
return javascriptable_file;
|
115
|
+
}
|
116
|
+
|
117
|
+
}
|
118
|
+
}
|
@@ -0,0 +1,111 @@
|
|
1
|
+
package com.nathancolgate.s3_swf_upload {
|
2
|
+
|
3
|
+
import com.elctech.S3UploadOptions;
|
4
|
+
import com.elctech.S3UploadRequest;
|
5
|
+
import flash.external.ExternalInterface;
|
6
|
+
import com.nathancolgate.s3_swf_upload.*;
|
7
|
+
import flash.net.*;
|
8
|
+
import flash.events.*;
|
9
|
+
|
10
|
+
public class S3Upload extends S3UploadRequest {
|
11
|
+
|
12
|
+
private var _upload_options:S3UploadOptions;
|
13
|
+
|
14
|
+
public function S3Upload(s3_upload_options:S3UploadOptions) {
|
15
|
+
super(s3_upload_options);
|
16
|
+
|
17
|
+
_upload_options = s3_upload_options;
|
18
|
+
|
19
|
+
addEventListener(Event.OPEN, openHandler);
|
20
|
+
addEventListener(ProgressEvent.PROGRESS, progressHandler);
|
21
|
+
addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
|
22
|
+
addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
|
23
|
+
addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
|
24
|
+
addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, completeHandler);
|
25
|
+
|
26
|
+
try {
|
27
|
+
var next_file:FileReference = FileReference(Globals.queue.getItemAt(0));
|
28
|
+
this.upload(next_file);
|
29
|
+
} catch(error:Error) {
|
30
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadError',_upload_options,error);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
// called after the file is opened before _upload_options
|
35
|
+
private function openHandler(event:Event):void{
|
36
|
+
// This should only happen once per file
|
37
|
+
// But sometimes, after stopping and restarting the queeue
|
38
|
+
// It gets called multiple times
|
39
|
+
// BUG BUG BUG!
|
40
|
+
// ExternalInterface.call('s3_swf.jsLog','openHandler');
|
41
|
+
// ExternalInterface.call('s3_swf.jsLog','Calling onUploadOpen...');
|
42
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadOpen',_upload_options,event);
|
43
|
+
// ExternalInterface.call('s3_swf.jsLog','onUploadOpen called');
|
44
|
+
}
|
45
|
+
|
46
|
+
// called during the file _upload_options of each file being _upload_optionsed
|
47
|
+
// we use this to feed the progress bar its data
|
48
|
+
private function progressHandler(progress_event:ProgressEvent):void {
|
49
|
+
// ExternalInterface.call('s3_swf.jsLog','progressHandler');
|
50
|
+
// ExternalInterface.call('s3_swf.jsLog','Calling onUploadProgress...');
|
51
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadProgress',_upload_options,progress_event);
|
52
|
+
// ExternalInterface.call('s3_swf.jsLog','onUploadProgress called');
|
53
|
+
}
|
54
|
+
|
55
|
+
// only called if there is an error detected by flash player browsing or _upload_optionsing a file
|
56
|
+
private function ioErrorHandler(io_error_event:IOErrorEvent):void{
|
57
|
+
// ExternalInterface.call('s3_swf.jsLog','ioErrorHandler');
|
58
|
+
// ExternalInterface.call('s3_swf.jsLog','Calling onUploadIOError...');
|
59
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadIOError',_upload_options,io_error_event);
|
60
|
+
// ExternalInterface.call('s3_swf.jsLog','onUploadIOError called');
|
61
|
+
}
|
62
|
+
|
63
|
+
private function httpStatusHandler(http_status_event:HTTPStatusEvent):void {
|
64
|
+
// ExternalInterface.call('s3_swf.jsLog','httpStatusHandler');
|
65
|
+
// ExternalInterface.call('s3_swf.jsLog','Calling onUploadHttpStatus...');
|
66
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadHttpStatus',_upload_options,http_status_event);
|
67
|
+
// ExternalInterface.call('s3_swf.jsLog','onUploadHttpStatus called');
|
68
|
+
}
|
69
|
+
|
70
|
+
// only called if a security error detected by flash player such as a sandbox violation
|
71
|
+
private function securityErrorHandler(security_error_event:SecurityErrorEvent):void{
|
72
|
+
// ExternalInterface.call('s3_swf.jsLog','securityErrorHandler');
|
73
|
+
// ExternalInterface.call('s3_swf.jsLog','Calling onUploadSecurityError...');
|
74
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadSecurityError',_upload_options,security_error_event);
|
75
|
+
// ExternalInterface.call('s3_swf.jsLog','onUploadSecurityError called');
|
76
|
+
}
|
77
|
+
|
78
|
+
private function completeHandler(event:Event):void{
|
79
|
+
// prepare to destroy
|
80
|
+
removeListeners();
|
81
|
+
removeEventListener(Event.OPEN, openHandler);
|
82
|
+
removeEventListener(ProgressEvent.PROGRESS, progressHandler);
|
83
|
+
removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
|
84
|
+
removeEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
|
85
|
+
removeEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
|
86
|
+
removeEventListener(DataEvent.UPLOAD_COMPLETE_DATA, completeHandler);
|
87
|
+
|
88
|
+
// callback
|
89
|
+
// ExternalInterface.call('s3_swf.jsLog','completeHandler');
|
90
|
+
// ExternalInterface.call('s3_swf.jsLog','Calling onUploadComplete...');
|
91
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadComplete',_upload_options,event);
|
92
|
+
// ExternalInterface.call('s3_swf.jsLog','onUploadComplete called');
|
93
|
+
// ExternalInterface.call('s3_swf.jsLog','Removing item from global queue...');
|
94
|
+
|
95
|
+
// destroy
|
96
|
+
Globals.queue.removeItemAt(0);
|
97
|
+
|
98
|
+
// ExternalInterface.call('s3_swf.jsLog','Item removed from global queue');
|
99
|
+
if (Globals.queue.length > 0){
|
100
|
+
// ExternalInterface.call('s3_swf.jsLog','Uploading next item in global queue...');
|
101
|
+
Globals.queue.uploadNextFile();
|
102
|
+
// ExternalInterface.call('s3_swf.jsLog','Next ttem in global queue uploaded');
|
103
|
+
} else {
|
104
|
+
// ExternalInterface.call('s3_swf.jsLog','Calling onUploadingFinish...');
|
105
|
+
ExternalInterface.call(S3Uploader.s3_swf_obj+'.onUploadingFinish');
|
106
|
+
// ExternalInterface.call('s3_swf.jsLog','onUploadingFinish called');
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
}
|
111
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 's3_swf_upload'
|
2
|
+
require 'rails'
|
3
|
+
|
4
|
+
module S3SwfUpload
|
5
|
+
class Railtie < Rails::Railtie
|
6
|
+
|
7
|
+
initializer "s3_swf_upload.load_s3_swf_upload_config" do
|
8
|
+
S3SwfUpload::S3Config.load_config
|
9
|
+
end
|
10
|
+
|
11
|
+
generators do
|
12
|
+
require "s3_swf_upload/railties/generators/uploader/uploader_generator"
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
module S3SwfUpload
|
4
|
+
module Generators
|
5
|
+
class Base < Rails::Generators::Base #:nodoc:
|
6
|
+
|
7
|
+
def self.source_root
|
8
|
+
# puts '****'
|
9
|
+
# puts File.expand_path(File.join(File.dirname(__FILE__), generator_name, 'templates'))
|
10
|
+
File.expand_path(File.join(File.dirname(__FILE__),generator_name, 'templates'))
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.banner
|
14
|
+
"#{$0} generate s3_swf_upload:#{generator_name} #{self.arguments.map{ |a| a.usage }.join(' ')}"
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
development:
|
2
|
+
bucket:
|
3
|
+
access_key_id:
|
4
|
+
secret_access_key:
|
5
|
+
max_file_size: 10485760
|
6
|
+
acl: public-read
|
7
|
+
|
8
|
+
test:
|
9
|
+
bucket:
|
10
|
+
access_key_id:
|
11
|
+
secret_access_key:
|
12
|
+
max_file_size: 10485760
|
13
|
+
acl: public-read
|
14
|
+
|
15
|
+
production:
|
16
|
+
bucket:
|
17
|
+
access_key_id:
|
18
|
+
secret_access_key:
|
19
|
+
max_file_size: 10485760
|
20
|
+
acl: public-read
|
@@ -0,0 +1,118 @@
|
|
1
|
+
/* SWFObject v2.2 <http://code.google.com/p/swfobject/>
|
2
|
+
is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
|
3
|
+
*/
|
4
|
+
var s3_upload_swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y<X;Y++){U[Y]()}}function K(X){if(J){X()}else{U[U.length]=X}}function s(Y){if(typeof O.addEventListener!=D){O.addEventListener("load",Y,false)}else{if(typeof j.addEventListener!=D){j.addEventListener("load",Y,false)}else{if(typeof O.attachEvent!=D){i(O,"onload",Y)}else{if(typeof O.onload=="function"){var X=O.onload;O.onload=function(){X();Y()}}else{O.onload=Y}}}}}function h(){if(T){V()}else{H()}}function V(){var X=j.getElementsByTagName("body")[0];var aa=C(r);aa.setAttribute("type",q);var Z=X.appendChild(aa);if(Z){var Y=0;(function(){if(typeof Z.GetVariable!=D){var ab=Z.GetVariable("$version");if(ab){ab=ab.split(" ")[1].split(",");M.pv=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}else{if(Y<10){Y++;setTimeout(arguments.callee,10);return}}X.removeChild(aa);Z=null;H()})()}else{H()}}function H(){var ag=o.length;if(ag>0){for(var af=0;af<ag;af++){var Y=o[af].id;var ab=o[af].callbackFn;var aa={success:false,id:Y};if(M.pv[0]>0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad<ac;ad++){if(X[ad].getAttribute("name").toLowerCase()!="movie"){ah[X[ad].getAttribute("name")]=X[ad].getAttribute("value")}}P(ai,ah,Y,ab)}else{p(ae);if(ab){ab(aa)}}}}}else{w(Y,true);if(ab){var Z=z(Y);if(Z&&typeof Z.SetVariable!=D){aa.success=true;aa.ref=Z}ab(aa)}}}}}function z(aa){var X=null;var Y=c(aa);if(Y&&Y.nodeName=="OBJECT"){if(typeof Y.SetVariable!=D){X=Y}else{var Z=Y.getElementsByTagName(r)[0];if(Z){X=Z}}}return X}function A(){return !a&&F("6.0.65")&&(M.win||M.mac)&&!(M.wk&&M.wk<312)}function P(aa,ab,X,Z){a=true;E=Z||null;B={success:false,id:X};var ae=c(X);if(ae){if(ae.nodeName=="OBJECT"){l=g(ae);Q=null}else{l=ae;Q=X}aa.id=R;if(typeof aa.width==D||(!/%$/.test(aa.width)&&parseInt(aa.width,10)<310)){aa.width="310"}if(typeof aa.height==D||(!/%$/.test(aa.height)&&parseInt(aa.height,10)<137)){aa.height="137"}j.title=j.title.slice(0,47)+" - Flash Player Installation";var ad=M.ie&&M.win?"ActiveX":"PlugIn",ac="MMredirectURL="+O.location.toString().replace(/&/g,"%26")+"&MMplayerType="+ad+"&MMdoctitle="+j.title;if(typeof ab.flashvars!=D){ab.flashvars+="&"+ac}else{ab.flashvars=ac}if(M.ie&&M.win&&ae.readyState!=4){var Y=C("div");X+="SWFObjectNew";Y.setAttribute("id",X);ae.parentNode.insertBefore(Y,ae);ae.style.display="none";(function(){if(ae.readyState==4){ae.parentNode.removeChild(ae)}else{setTimeout(arguments.callee,10)}})()}u(aa,ab,X)}}function p(Y){if(M.ie&&M.win&&Y.readyState!=4){var X=C("div");Y.parentNode.insertBefore(X,Y);X.parentNode.replaceChild(g(Y),X);Y.style.display="none";(function(){if(Y.readyState==4){Y.parentNode.removeChild(Y)}else{setTimeout(arguments.callee,10)}})()}else{Y.parentNode.replaceChild(g(Y),Y)}}function g(ab){var aa=C("div");if(M.win&&M.ie){aa.innerHTML=ab.innerHTML}else{var Y=ab.getElementsByTagName(r)[0];if(Y){var ad=Y.childNodes;if(ad){var X=ad.length;for(var Z=0;Z<X;Z++){if(!(ad[Z].nodeType==1&&ad[Z].nodeName=="PARAM")&&!(ad[Z].nodeType==8)){aa.appendChild(ad[Z].cloneNode(true))}}}}}return aa}function u(ai,ag,Y){var X,aa=c(Y);if(M.wk&&M.wk<312){return X}if(aa){if(typeof ai.id==D){ai.id=Y}if(M.ie&&M.win){var ah="";for(var ae in ai){if(ai[ae]!=Object.prototype[ae]){if(ae.toLowerCase()=="data"){ag.movie=ai[ae]}else{if(ae.toLowerCase()=="styleclass"){ah+=' class="'+ai[ae]+'"'}else{if(ae.toLowerCase()!="classid"){ah+=" "+ae+'="'+ai[ae]+'"'}}}}}var af="";for(var ad in ag){if(ag[ad]!=Object.prototype[ad]){af+='<param name="'+ad+'" value="'+ag[ad]+'" />'}}aa.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+ah+">"+af+"</object>";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab<ac;ab++){I[ab][0].detachEvent(I[ab][1],I[ab][2])}var Z=N.length;for(var aa=0;aa<Z;aa++){y(N[aa])}for(var Y in M){M[Y]=null}M=null;for(var X in swfobject){swfobject[X]=null}swfobject=null})}}();return{registerObject:function(ab,X,aa,Z){if(M.w3&&ab&&X){var Y={};Y.id=ab;Y.swfVersion=X;Y.expressInstall=aa;Y.callbackFn=Z;o[o.length]=Y;w(ab,false)}else{if(Z){Z({success:false,id:ab})}}},getObjectById:function(X){if(M.w3){return z(X)}},embedSWF:function(ab,ah,ae,ag,Y,aa,Z,ad,af,ac){var X={success:false,id:ah};if(M.w3&&!(M.wk&&M.wk<312)&&ab&&ah&&ae&&ag&&Y){w(ah,false);K(function(){ae+="";ag+="";var aj={};if(af&&typeof af===r){for(var al in af){aj[al]=af[al]}}aj.data=ab;aj.width=ae;aj.height=ag;var am={};if(ad&&typeof ad===r){for(var ak in ad){am[ak]=ad[ak]}}if(Z&&typeof Z===r){for(var ai in Z){if(typeof am.flashvars!=D){am.flashvars+="&"+ai+"="+Z[ai]}else{am.flashvars=ai+"="+Z[ai]}}}if(F(Y)){var an=u(aj,am,ah);if(aj.id==ah){w(ah,true)}X.success=true;X.ref=an}else{if(aa&&A()){aj.data=aa;P(aj,am,ah,ac);return}else{w(ah,true)}}if(ac){ac(X)}})}else{if(ac){ac(X)}}},switchOffAutoHideShow:function(){m=false},ua:M,getFlashPlayerVersion:function(){return{major:M.pv[0],minor:M.pv[1],release:M.pv[2]}},hasFlashPlayerVersion:F,createSWF:function(Z,Y,X){if(M.w3){return u(Z,Y,X)}else{return undefined}},showExpressInstall:function(Z,aa,X,Y){if(M.w3&&A()){P(Z,aa,X,Y)}},removeSWF:function(X){if(M.w3){y(X)}},createCSS:function(aa,Z,Y,X){if(M.w3){v(aa,Z,Y,X)}},addDomLoadEvent:K,addLoadEvent:s,getQueryParamValue:function(aa){var Z=j.location.search||j.location.hash;if(Z){if(/\?/.test(Z)){Z=Z.split("?")[1]}if(aa==null){return L(Z)}var Y=Z.split("&");for(var X=0;X<Y.length;X++){if(Y[X].substring(0,Y[X].indexOf("="))==aa){return L(Y[X].substring((Y[X].indexOf("=")+1)))}}}return""},expressInstallCallback:function(){if(a){var X=c(R);if(X&&l){X.parentNode.replaceChild(l,X);if(Q){w(Q,true);if(M.ie&&M.win){l.style.display="block"}}if(E){E(B)}}a=false}}}}();
|
5
|
+
|
6
|
+
/* S3_Upload V0.1
|
7
|
+
Copyright (c) 2008 Elctech,
|
8
|
+
This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
|
9
|
+
*/
|
10
|
+
/* S3_Upload V0.2
|
11
|
+
Copyright (c) 2010 Nathan Colgate,
|
12
|
+
This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
|
13
|
+
*/
|
14
|
+
var s3_swf;
|
15
|
+
function s3_swf_init(id, options)
|
16
|
+
{
|
17
|
+
var buttonWidth = (options.buttonWidth != undefined) ? options.buttonWidth : 50;
|
18
|
+
var buttonHeight = (options.buttonHeight != undefined) ? options.buttonHeight : 50;
|
19
|
+
var flashVersion = (options.flashVersion != undefined) ? options.flashVersion : '9.0.0';
|
20
|
+
var queueSizeLimit = (options.queueSizeLimit != undefined) ? options.queueSizeLimit : 10;
|
21
|
+
var fileSizeLimit = (options.fileSizeLimit != undefined) ? options.fileSizeLimit : 524288000;
|
22
|
+
var fileTypes = (options.fileTypes != undefined) ? options.fileTypes : "*.*";
|
23
|
+
var fileTypeDescs = (options.fileTypeDescs != undefined) ? options.fileTypeDescs : "All Files";
|
24
|
+
var selectMultipleFiles = (options.selectMultipleFiles != undefined) ? options.selectMultipleFiles : true;
|
25
|
+
var keyPrefix = (options.keyPrefix != undefined) ? options.keyPrefix : "";
|
26
|
+
var signaturePath = (options.signaturePath != undefined) ? options.signaturePath : "s3_uploads.xml";
|
27
|
+
var swfFilePath = (options.swfFilePath != undefined) ? options.swfFilePath : "/flash/s3_upload.swf";
|
28
|
+
var buttonUpPath = (options.buttonUpPath != undefined) ? options.buttonUpPath : "";
|
29
|
+
var buttonOverPath = (options.buttonOverPath != undefined) ? options.buttonOverPath : "";
|
30
|
+
var buttonDownPath = (options.buttonDownPath != undefined) ? options.buttonDownPath : "";
|
31
|
+
|
32
|
+
var onFileAdd = (options.onFileAdd != undefined) ? options.onFileAdd : function(file){};
|
33
|
+
var onFileRemove = (options.onFileRemove != undefined) ? options.onFileRemove : function(file){};
|
34
|
+
var onFileSizeLimitReached = (options.onFileSizeLimitReached != undefined) ? options.onFileSizeLimitReached : function(file){};
|
35
|
+
var onFileNotInQueue = (options.onFileNotInQueue != undefined) ? options.onFileNotInQueue : function(file){};
|
36
|
+
|
37
|
+
var onQueueChange = (options.onQueueChange != undefined) ? options.onQueueChange : function(queue){};
|
38
|
+
var onQueueClear = (options.onQueueClear != undefined) ? options.onQueueClear : function(queue){};
|
39
|
+
var onQueueSizeLimitReached = (options.onQueueSizeLimitReached != undefined) ? options.onQueueSizeLimitReached : function(queue){};
|
40
|
+
var onQueueEmpty = (options.onQueueEmpty != undefined) ? options.onQueueEmpty : function(queue){};
|
41
|
+
|
42
|
+
var onUploadingStop = (options.onUploadingStop != undefined) ? options.onUploadingStop : function(){};
|
43
|
+
var onUploadingStart = (options.onUploadingStart != undefined) ? options.onUploadingStart : function(){};
|
44
|
+
var onUploadingFinish = (options.onUploadingFinish != undefined) ? options.onUploadingFinish : function(){};
|
45
|
+
|
46
|
+
var onSignatureOpen = (options.onSignatureOpen != undefined) ? options.onSignatureOpen : function(file,event){};
|
47
|
+
var onSignatureProgress = (options.onSignatureProgress != undefined) ? options.onSignatureProgress : function(file,progress_event){};
|
48
|
+
var onSignatureHttpStatus = (options.onSignatureHttpStatus != undefined) ? options.onSignatureHttpStatus : function(file,http_status_event){};
|
49
|
+
var onSignatureComplete = (options.onSignatureComplete != undefined) ? options.onSignatureComplete : function(file,event){};
|
50
|
+
var onSignatureSecurityError = (options.onSignatureSecurityError != undefined) ? options.onSignatureSecurityError : function(file,security_error_event){};
|
51
|
+
var onSignatureIOError = (options.onSignatureIOError != undefined) ? options.onSignatureIOError : function(file,io_error_event){};
|
52
|
+
var onSignatureXMLError = (options.onSignatureXMLError != undefined) ? options.onSignatureXMLError : function(file,error_message){};
|
53
|
+
|
54
|
+
var onUploadOpen = (options.onUploadOpen != undefined) ? options.onUploadOpen : function(upload_options,event){};
|
55
|
+
var onUploadProgress = (options.onUploadProgress != undefined) ? options.onUploadProgress : function(upload_options,progress_event){};
|
56
|
+
var onUploadHttpStatus = (options.onUploadHttpStatus != undefined) ? options.onUploadHttpStatus : function(upload_options,http_status_event){};
|
57
|
+
var onUploadComplete = (options.onUploadComplete != undefined) ? options.onUploadComplete : function(upload_options,event){};
|
58
|
+
var onUploadIOError = (options.onUploadIOError != undefined) ? options.onUploadIOError : function(upload_options,io_error_event){};
|
59
|
+
var onUploadSecurityError = (options.onUploadSecurityError != undefined) ? options.onUploadSecurityError : function(upload_options,security_error_event){};
|
60
|
+
var onUploadError = (options.onUploadError != undefined) ? options.onUploadError : function(upload_options,error){};
|
61
|
+
|
62
|
+
var flashvars = {"s3_swf_obj": (options.swfVarObj != undefined ? options.swfVarObj : 's3_swf')}; //fallback to the global var incase script is used outside of view helper
|
63
|
+
var params = {};
|
64
|
+
var attributes = {};
|
65
|
+
params.wmode = "transparent";
|
66
|
+
params.menu = "false";
|
67
|
+
params.quality = "low";
|
68
|
+
|
69
|
+
s3_upload_swfobject.embedSWF(swfFilePath+"?t=" + new Date().getTime(), id, buttonWidth, buttonHeight, flashVersion, false, flashvars, params, attributes);
|
70
|
+
|
71
|
+
var signatureUrl = window.location.protocol + '//' + window.location.host + signaturePath;
|
72
|
+
var buttonUpUrl = window.location.protocol + '//' + window.location.host + buttonUpPath;
|
73
|
+
var buttonDownUrl = window.location.protocol + '//' + window.location.host + buttonDownPath;
|
74
|
+
var buttonOverUrl = window.location.protocol + '//' + window.location.host + buttonOverPath;
|
75
|
+
|
76
|
+
s3_swf = {
|
77
|
+
obj: function() { return document[id]; },
|
78
|
+
|
79
|
+
init: function() { this.obj().init(signatureUrl, keyPrefix, fileSizeLimit, queueSizeLimit, fileTypes, fileTypeDescs, selectMultipleFiles,buttonWidth,buttonHeight,buttonUpUrl,buttonDownUrl,buttonOverUrl); },
|
80
|
+
clearQueue: function() { this.obj().clearQueue();},
|
81
|
+
startUploading: function() { this.obj().startUploading();},
|
82
|
+
stopUploading: function() { this.obj().stopUploading();},
|
83
|
+
removeFileFromQueue: function(index) { this.obj().removeFileFromQueue(index); },
|
84
|
+
|
85
|
+
onFileAdd: onFileAdd,
|
86
|
+
onFileRemove: onFileRemove,
|
87
|
+
onFileSizeLimitReached: onFileSizeLimitReached,
|
88
|
+
onFileNotInQueue: onFileNotInQueue,
|
89
|
+
|
90
|
+
onQueueChange: onQueueChange,
|
91
|
+
onQueueClear: onQueueClear,
|
92
|
+
onQueueSizeLimitReached: onQueueSizeLimitReached,
|
93
|
+
onQueueEmpty: onQueueEmpty,
|
94
|
+
|
95
|
+
onUploadingStop: onUploadingStop,
|
96
|
+
onUploadingStart: onUploadingStart,
|
97
|
+
onUploadingFinish: onUploadingFinish,
|
98
|
+
|
99
|
+
onSignatureOpen: onSignatureOpen,
|
100
|
+
onSignatureProgress: onSignatureProgress,
|
101
|
+
onSignatureHttpStatus: onSignatureHttpStatus,
|
102
|
+
onSignatureComplete: onSignatureComplete,
|
103
|
+
onSignatureSecurityError: onSignatureSecurityError,
|
104
|
+
onSignatureIOError: onSignatureIOError,
|
105
|
+
onSignatureXMLError: onSignatureXMLError,
|
106
|
+
|
107
|
+
onUploadOpen: onUploadOpen,
|
108
|
+
onUploadProgress: onUploadProgress,
|
109
|
+
onUploadHttpStatus: onUploadHttpStatus,
|
110
|
+
onUploadComplete: onUploadComplete,
|
111
|
+
onUploadIOError: onUploadIOError,
|
112
|
+
onUploadSecurityError: onUploadSecurityError,
|
113
|
+
onUploadError: onUploadError
|
114
|
+
|
115
|
+
}
|
116
|
+
|
117
|
+
return(s3_swf);
|
118
|
+
}
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
class S3UploadsController < ApplicationController
|
4
|
+
|
5
|
+
# You might want to look at https and expiration_date below.
|
6
|
+
# Possibly these should also be configurable from S3Config...
|
7
|
+
|
8
|
+
skip_before_filter :verify_authenticity_token
|
9
|
+
include S3SwfUpload::Signature
|
10
|
+
|
11
|
+
def index
|
12
|
+
bucket = S3SwfUpload::S3Config.bucket
|
13
|
+
access_key_id = S3SwfUpload::S3Config.access_key_id
|
14
|
+
acl = S3SwfUpload::S3Config.acl
|
15
|
+
secret_key = S3SwfUpload::S3Config.secret_access_key
|
16
|
+
key = params[:key]
|
17
|
+
content_type = params[:content_type]
|
18
|
+
https = 'false'
|
19
|
+
error_message = ''
|
20
|
+
expiration_date = 1.hours.from_now.utc.strftime('%Y-%m-%dT%H:%M:%S.000Z')
|
21
|
+
|
22
|
+
policy = Base64.encode64(
|
23
|
+
"{
|
24
|
+
'expiration': '#{expiration_date}',
|
25
|
+
'conditions': [
|
26
|
+
{'bucket': '#{bucket}'},
|
27
|
+
{'key': '#{key}'},
|
28
|
+
{'acl': '#{acl}'},
|
29
|
+
{'Content-Type': '#{content_type}'},
|
30
|
+
{'Content-Disposition': 'attachment'},
|
31
|
+
['starts-with', '$Filename', ''],
|
32
|
+
['eq', '$success_action_status', '201']
|
33
|
+
]
|
34
|
+
}").gsub(/\n|\r/, '')
|
35
|
+
|
36
|
+
signature = b64_hmac_sha1(secret_key, policy)
|
37
|
+
|
38
|
+
respond_to do |format|
|
39
|
+
format.xml {
|
40
|
+
render :xml => {
|
41
|
+
:policy => policy,
|
42
|
+
:signature => signature,
|
43
|
+
:bucket => bucket,
|
44
|
+
:accesskeyid => access_key_id,
|
45
|
+
:acl => acl,
|
46
|
+
:expirationdate => expiration_date,
|
47
|
+
:https => https,
|
48
|
+
:errorMessage => error_message.to_s
|
49
|
+
}.to_xml
|
50
|
+
}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 's3_swf_upload/railties/generators/s3_swf_upload'
|
2
|
+
|
3
|
+
module S3SwfUpload
|
4
|
+
module Generators
|
5
|
+
class UploaderGenerator < Base
|
6
|
+
|
7
|
+
def create_uploader
|
8
|
+
copy_file 'amazon_s3.yml', File.join('config','amazon_s3.yml')
|
9
|
+
copy_file 's3_uploads_controller.rb', File.join('app','controllers', 's3_uploads_controller.rb')
|
10
|
+
copy_file 's3_upload.js', File.join('public','javascripts', 's3_upload.js')
|
11
|
+
copy_file 's3_upload.swf', File.join('public','flash', 's3_upload.swf')
|
12
|
+
copy_file 's3_up_button.gif', File.join('public','flash', 's3_up_button.gif')
|
13
|
+
copy_file 's3_down_button.gif', File.join('public','flash', 's3_down_button.gif')
|
14
|
+
copy_file 's3_over_button.gif', File.join('public','flash', 's3_over_button.gif')
|
15
|
+
route "resources :s3_uploads"
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module S3SwfUpload
|
2
|
+
class S3Config
|
3
|
+
require 'erb' unless defined?(ERB)
|
4
|
+
require 'yaml' unless defined?(YAML)
|
5
|
+
|
6
|
+
cattr_reader :access_key_id, :secret_access_key
|
7
|
+
cattr_accessor :bucket, :max_file_size, :acl
|
8
|
+
|
9
|
+
def self.load_config
|
10
|
+
begin
|
11
|
+
filename = "#{Rails.root}/config/amazon_s3.yml"
|
12
|
+
|
13
|
+
buf = IO.read(filename)
|
14
|
+
expanded = ERB.new(buf).result(binding)
|
15
|
+
config = YAML.load(expanded)[Rails.env]
|
16
|
+
|
17
|
+
if config == nil
|
18
|
+
raise "Could not load config options for #{Rails.env} from #{filename}."
|
19
|
+
end
|
20
|
+
|
21
|
+
@@access_key_id = config['access_key_id'] || ENV['AWS_ACCESS_KEY_ID']
|
22
|
+
@@secret_access_key = config['secret_access_key'] || ENV['AWS_SECRET_ACCESS_KEY']
|
23
|
+
@@bucket = config['bucket']
|
24
|
+
@@max_file_size = config['max_file_size']
|
25
|
+
@@acl = config['acl'] || 'private'
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
unless @@access_key_id && @@secret_access_key && @@bucket
|
30
|
+
raise "Please configure your S3 settings in #{filename} before continuing so that S3 SWF Upload can function properly."
|
31
|
+
end
|
32
|
+
rescue Errno::ENOENT
|
33
|
+
# Using put inside a rake task may mess with some rake tasks
|
34
|
+
# According to: https://github.com/mhodgson/s3-swf-upload-plugin/commit/f5cc849e1d8b43c1f0d30eb92b772c10c9e73891
|
35
|
+
# Going to comment this out for the time being
|
36
|
+
# NCC@BNB - 11/16/10
|
37
|
+
# No config file yet. Not a big deal. Just issue a warning
|
38
|
+
# puts "WARNING: You are using the S3 SWF Uploader gem, which wants a config file at #{filename}, " +
|
39
|
+
# "but none could be found. You should try running 'rails generate s3_swf_upload:uploader'"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|