attache_client 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: abdd59a8e946383476ec8c58434d94d6ce7bf6e7
4
- data.tar.gz: 6000e846b291c03ac6e342a07542c3c5f576d48f
3
+ metadata.gz: 85797f28c584f9b228fa2109cd30bd897f1fb722
4
+ data.tar.gz: 9d8bcc930c642e7b53ff2103bd847b7d6e3590fd
5
5
  SHA512:
6
- metadata.gz: dc24bb5c8b9258028c6c26f9a8f0c784a53df709db4d4f18160222bf6d9f1335eaa4b489673384a7b4d7cb79e6279bbf2f049fc0b891c8e4b5b675ef043ceaa6
7
- data.tar.gz: 965fa0058c8317449d2c4681dc382a07758c62423a7797982079d2fad88b371f7ee90d54af048ca035ca48e1cb48402c866cd47e9efdc9691b71cc0bf2ff57fc
6
+ metadata.gz: b62f1989a4eac6e82ca9b155694535f73c6eb88f6a9f4f3bc70898ab4172dbb3504f94806912a9b15c49b573d143d01012b5c7443e8b1415af3be06c753c3474
7
+ data.tar.gz: 7d5f934642057ba36dd4ce6c9a79d29fc8899d03e156805012885652f1e487e4a9e9ff69b7b21cac4c1ab3034ba0ee953530523d75c5641a3c4d670219af54f1
data/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Ruby on Rails integration for [attache server](https://github.com/choonkeat/attache)
4
4
 
5
+ NOTE: You can learn how to use this gem by looking at the [changes made to our example app](https://github.com/choonkeat/attache-railsapp/commit/16cb1274dcce5be01b6c9d42ad60c30c106ad7f9) or follow the step by step instructions in this `README`
6
+
5
7
  ## Dependencies
6
8
 
7
9
  [React](https://github.com/reactjs/react-rails), jQuery, Bootstrap 3
@@ -123,6 +125,20 @@ Alternatively, you can get the list of urls and manipulate it however you want
123
125
  = image_tag attache_urls(@user.photo_path, '128x128#').sample
124
126
  ```
125
127
 
128
+ ### Environment configs
129
+
130
+ `ATTACHE_UPLOAD_URL` points to the attache server upload url. e.g. `http://localhost:9292/upload`
131
+
132
+ `ATTACHE_DOWNLOAD_URL` points to url prefix for downloading the resized images, e.g. `http://cdn.lvh.me:9292/view`
133
+
134
+ `ATTACHE_UPLOAD_DURATION` refers to the number of seconds before a signed upload request is considered expired, e.g. `600`
135
+
136
+ `ATTACHE_SECRET_KEY` is the shared secret with the `attache` server. e.g. `t0psecr3t`
137
+
138
+ * If this variable is not set, then upload requests will not be signed & `ATTACHE_UPLOAD_DURATION` will be ignored
139
+ * If this variable is set, it must be the same value as `SECRET_KEY` is set on the `attache` server
140
+
141
+
126
142
  # License
127
143
 
128
144
  MIT
@@ -23,9 +23,10 @@ var AttacheFileInput = React.createClass({displayName: "AttacheFileInput",
23
23
  this.state.files = {};
24
24
  this.setState(this.state);
25
25
  // upload the file via CORS
26
+ var that = this;
26
27
  new CORSUpload({
27
28
  file_element: file_element, onComplete: this.setFileValue, onProgress: this.setFileValue,
28
- onError: function(uid, status) { alert(status); }
29
+ onError: function(uid, status) { that.setFileValue(uid, { pctString: '90%', pctDesc: status, className: 'progress-bar progress-bar-danger' }); }
29
30
  });
30
31
  // we don't want the file binary to be uploaded in the main form
31
32
  file_element.value = '';
@@ -73,13 +74,13 @@ var AttacheFilePreview = React.createClass({displayName: "AttacheFilePreview",
73
74
  },
74
75
 
75
76
  render: function() {
76
- var className = "progress-bar progress-bar-striped active" + (this.props.src ? " progress-bar-success" : "");
77
- var pctString = (this.props.src ? 100 : this.props.percentLoaded) + "%";
78
- var pctDesc = (this.props.src ? 'Loading...' : pctString);
77
+ var className = this.props.className || "progress-bar progress-bar-striped active" + (this.props.src ? " progress-bar-success" : "");
78
+ var pctString = this.props.pctString || (this.props.src ? 100 : this.props.percentLoaded) + "%";
79
+ var pctDesc = this.props.pctDesc || (this.props.src ? 'Loading...' : pctString);
79
80
  var img = (this.props.src ? (React.createElement("img", {src: this.props.src, onLoad: this.removeProgressBar})) : '');
80
81
  var pctStyle = { width: pctString, minWidth: '3em' };
81
82
  var cptStyle = { textOverflow: "ellipsis" };
82
- var caption = React.createElement("div", {className: "pull-left", style: cptStyle}, this.props.filename || this.props.path.split('/').pop());
83
+ var caption = React.createElement("div", {className: "pull-left", style: cptStyle}, this.props.filename || this.props.path && this.props.path.split('/').pop());
83
84
 
84
85
  if (this.state.srcWas != this.props.src) {
85
86
  var progress = (
@@ -23,9 +23,10 @@ var AttacheFileInput = React.createClass({
23
23
  this.state.files = {};
24
24
  this.setState(this.state);
25
25
  // upload the file via CORS
26
+ var that = this;
26
27
  new CORSUpload({
27
28
  file_element: file_element, onComplete: this.setFileValue, onProgress: this.setFileValue,
28
- onError: function(uid, status) { alert(status); }
29
+ onError: function(uid, status) { that.setFileValue(uid, { pctString: '90%', pctDesc: status, className: 'progress-bar progress-bar-danger' }); }
29
30
  });
30
31
  // we don't want the file binary to be uploaded in the main form
31
32
  file_element.value = '';
@@ -73,13 +74,13 @@ var AttacheFilePreview = React.createClass({
73
74
  },
74
75
 
75
76
  render: function() {
76
- var className = "progress-bar progress-bar-striped active" + (this.props.src ? " progress-bar-success" : "");
77
- var pctString = (this.props.src ? 100 : this.props.percentLoaded) + "%";
78
- var pctDesc = (this.props.src ? 'Loading...' : pctString);
77
+ var className = this.props.className || "progress-bar progress-bar-striped active" + (this.props.src ? " progress-bar-success" : "");
78
+ var pctString = this.props.pctString || (this.props.src ? 100 : this.props.percentLoaded) + "%";
79
+ var pctDesc = this.props.pctDesc || (this.props.src ? 'Loading...' : pctString);
79
80
  var img = (this.props.src ? (<img src={this.props.src} onLoad={this.removeProgressBar} />) : '');
80
81
  var pctStyle = { width: pctString, minWidth: '3em' };
81
82
  var cptStyle = { textOverflow: "ellipsis" };
82
- var caption = <div className="pull-left" style={cptStyle}>{this.props.filename || this.props.path.split('/').pop()}</div>;
83
+ var caption = <div className="pull-left" style={cptStyle}>{this.props.filename || this.props.path && this.props.path.split('/').pop()}</div>;
83
84
 
84
85
  if (this.state.srcWas != this.props.src) {
85
86
  var progress = (
@@ -14,8 +14,17 @@ var CORSUpload = (function() {
14
14
  }
15
15
 
16
16
  CORSUpload.prototype.handleFileSelect = function(file_element) {
17
- var f, files, output, _i, _len, _results, url;
18
- url = $(file_element).data('uploadurl');
17
+ var f, files, output, _i, _len, _results, url, $ele;
18
+ $ele = $(file_element);
19
+ url = $ele.data('uploadurl');
20
+ if ($ele.data('hmac')) {
21
+ url = url +
22
+ "?hmac=" + encodeURIComponent($ele.data('hmac')) +
23
+ "&uuid=" + encodeURIComponent($ele.data('uuid')) +
24
+ "&expiration=" + encodeURIComponent($ele.data('expiration')) +
25
+ ""
26
+ }
27
+
19
28
  files = file_element.files;
20
29
  output = [];
21
30
  _results = [];
@@ -45,7 +54,8 @@ var CORSUpload = (function() {
45
54
  CORSUpload.prototype.performUpload = function(file, url) {
46
55
  var this_s3upload, xhr;
47
56
  this_s3upload = this;
48
- xhr = this.createCORSRequest('PUT', url + (url.indexOf('?') == -1 ? '?' : '&') + 'file=' + encodeURIComponent(file.name));
57
+ url = url + (url.indexOf('?') == -1 ? '?' : '&') + 'file=' + encodeURIComponent(file.name);
58
+ xhr = this.createCORSRequest('PUT', url);
49
59
  if (!xhr) {
50
60
  this.onError(file.uid, 'CORS not supported');
51
61
  } else {
@@ -53,11 +63,11 @@ var CORSUpload = (function() {
53
63
  if (xhr.status === 200) {
54
64
  this_s3upload.onComplete(file.uid, JSON.parse(e.target.responseText));
55
65
  } else {
56
- return this_s3upload.onError(file.uid, 'Upload error: ' + xhr.status);
66
+ return this_s3upload.onError(file.uid, xhr.status + ' ' + xhr.statusText);
57
67
  }
58
68
  };
59
69
  xhr.onerror = function() {
60
- return this_s3upload.onError(file.uid, 'XHR error.');
70
+ return this_s3upload.onError(file.uid, 'Unable to reach server');
61
71
  };
62
72
  xhr.upload.onprogress = function(e) {
63
73
  var percentLoaded;
@@ -4,6 +4,7 @@ module AttacheClient
4
4
  module ViewHelper
5
5
  ATTACHE_UPLOAD_URL = ENV.fetch('ATTACHE_UPLOAD_URL') { 'http://localhost:9292/upload' }
6
6
  ATTACHE_DOWNLOAD_URL = ENV.fetch('ATTACHE_DOWNLOAD_URL') { 'http://localhost:9292/view' }
7
+ ATTACHE_UPLOAD_DURATION = ENV.fetch('ATTACHE_UPLOAD_DURATION') { '600' }.to_i # 10 minutes
7
8
 
8
9
  def attache_urls(json, geometry)
9
10
  array = json.kind_of?(Array) ? json : [*json]
@@ -17,6 +18,15 @@ module AttacheClient
17
18
  end
18
19
 
19
20
  def attache_options(geometry, current_value)
21
+ auth = if ENV['ATTACHE_SECRET_KEY']
22
+ uuid = SecureRandom.uuid
23
+ expiration = (Time.now + ATTACHE_UPLOAD_DURATION).to_i
24
+ hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), ENV['ATTACHE_SECRET_KEY'], "#{uuid}#{expiration}")
25
+ { uuid: uuid, expiration: expiration, hmac: hmac }
26
+ else
27
+ {}
28
+ end
29
+
20
30
  {
21
31
  class: 'enable-attache',
22
32
  data: {
@@ -24,7 +34,7 @@ module AttacheClient
24
34
  value: [*current_value],
25
35
  uploadurl: ATTACHE_UPLOAD_URL,
26
36
  downloadurl: ATTACHE_DOWNLOAD_URL,
27
- },
37
+ }.merge(auth),
28
38
  }
29
39
  end
30
40
  end
@@ -1,3 +1,3 @@
1
1
  module AttacheClient
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attache_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - choonkeat
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-21 00:00:00.000000000 Z
11
+ date: 2015-02-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email: