attache_client 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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: