condo 1.0.6 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.textile +19 -32
- data/lib/condo.rb +124 -127
- data/lib/condo/configuration.rb +41 -76
- data/lib/condo/engine.rb +32 -39
- data/lib/condo/errors.rb +6 -8
- data/lib/condo/strata/amazon_s3.rb +246 -294
- data/lib/condo/strata/google_cloud_storage.rb +238 -272
- data/lib/condo/strata/open_stack_swift.rb +251 -0
- data/lib/condo/version.rb +1 -1
- metadata +31 -96
- data/app/assets/javascripts/condo.js +0 -9
- data/app/assets/javascripts/condo/amazon.js +0 -403
- data/app/assets/javascripts/condo/condo.js +0 -184
- data/app/assets/javascripts/condo/config.js +0 -69
- data/app/assets/javascripts/condo/google.js +0 -338
- data/app/assets/javascripts/condo/md5/hash.worker.emulator.js +0 -23
- data/app/assets/javascripts/condo/md5/hash.worker.js +0 -11
- data/app/assets/javascripts/condo/md5/hasher.js +0 -119
- data/app/assets/javascripts/condo/md5/spark-md5.js +0 -599
- data/app/assets/javascripts/condo/rackspace.js +0 -326
- data/app/assets/javascripts/condo/services/abstract-md5.js.erb +0 -86
- data/app/assets/javascripts/condo/services/base64.js +0 -184
- data/app/assets/javascripts/condo/services/broadcaster.js +0 -26
- data/app/assets/javascripts/condo/services/uploader.js +0 -302
- data/app/assets/javascripts/core/core.js +0 -4
- data/app/assets/javascripts/core/services/1-safe-apply.js +0 -17
- data/app/assets/javascripts/core/services/2-messaging.js +0 -171
- data/lib/condo/strata/rackspace_cloud_files.rb +0 -245
- data/test/condo_test.rb +0 -27
- data/test/dummy/README.rdoc +0 -261
- data/test/dummy/Rakefile +0 -7
- data/test/dummy/app/assets/javascripts/application.js +0 -15
- data/test/dummy/app/assets/stylesheets/application.css +0 -13
- data/test/dummy/app/controllers/application_controller.rb +0 -3
- data/test/dummy/app/helpers/application_helper.rb +0 -2
- data/test/dummy/app/views/layouts/application.html.erb +0 -14
- data/test/dummy/config.ru +0 -4
- data/test/dummy/config/application.rb +0 -59
- data/test/dummy/config/boot.rb +0 -10
- data/test/dummy/config/database.yml +0 -25
- data/test/dummy/config/environment.rb +0 -5
- data/test/dummy/config/environments/development.rb +0 -37
- data/test/dummy/config/environments/production.rb +0 -67
- data/test/dummy/config/environments/test.rb +0 -37
- data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
- data/test/dummy/config/initializers/inflections.rb +0 -15
- data/test/dummy/config/initializers/mime_types.rb +0 -5
- data/test/dummy/config/initializers/secret_token.rb +0 -7
- data/test/dummy/config/initializers/session_store.rb +0 -8
- data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
- data/test/dummy/config/locales/en.yml +0 -5
- data/test/dummy/config/routes.rb +0 -58
- data/test/dummy/public/404.html +0 -26
- data/test/dummy/public/422.html +0 -26
- data/test/dummy/public/500.html +0 -25
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +0 -6
- data/test/integration/navigation_test.rb +0 -10
- data/test/test_helper.rb +0 -15
@@ -1,26 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* CoTag Condo Amazon S3 Strategy
|
3
|
-
* Direct to cloud resumable uploads for Google Cloud Storage
|
4
|
-
*
|
5
|
-
* Copyright (c) 2012 CoTag Media.
|
6
|
-
*
|
7
|
-
* @author Stephen von Takach <steve@cotag.me>
|
8
|
-
* @copyright 2012 cotag.me
|
9
|
-
*
|
10
|
-
*
|
11
|
-
* References:
|
12
|
-
* *
|
13
|
-
*
|
14
|
-
**/
|
15
|
-
|
16
|
-
|
17
|
-
(function(angular, undefined) {
|
18
|
-
'use strict';
|
19
|
-
|
20
|
-
angular.module('Condo').
|
21
|
-
|
22
|
-
factory('Condo.Broadcast', ['$channel', function($channel) {
|
23
|
-
return $channel.openChannel('once unique');
|
24
|
-
}]);
|
25
|
-
|
26
|
-
})(angular);
|
@@ -1,302 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* CoTag Condo
|
3
|
-
* Direct to cloud resumable uploads
|
4
|
-
*
|
5
|
-
* Copyright (c) 2012 CoTag Media.
|
6
|
-
*
|
7
|
-
* @author Stephen von Takach <steve@cotag.me>
|
8
|
-
* @copyright 2012 cotag.me
|
9
|
-
*
|
10
|
-
*
|
11
|
-
* References:
|
12
|
-
* * http://docs.angularjs.org/api/ng.$http
|
13
|
-
* * http://docs.angularjs.org/api/ng.$q
|
14
|
-
*
|
15
|
-
**/
|
16
|
-
|
17
|
-
|
18
|
-
(function(jQuery, angular, undefined) { // jQuery required for progress event
|
19
|
-
'use strict';
|
20
|
-
|
21
|
-
angular.module('Condo').
|
22
|
-
|
23
|
-
//
|
24
|
-
// Implements the Condo API
|
25
|
-
//
|
26
|
-
provider('Condo.Api', function() {
|
27
|
-
|
28
|
-
var residencies = {};
|
29
|
-
|
30
|
-
this.register = function(provider_name, dependency) {
|
31
|
-
residencies[provider_name] = dependency;
|
32
|
-
};
|
33
|
-
|
34
|
-
|
35
|
-
this.$get = ['$http', '$rootScope', '$q', '$injector', function($http, $rootScope, $q, $injector) {
|
36
|
-
var token = $('meta[name="csrf-token"]').attr('content'),
|
37
|
-
|
38
|
-
|
39
|
-
condoConnection = function(api_endpoint, params) {
|
40
|
-
this.endpoint = api_endpoint; // The API mounting point
|
41
|
-
this.params = params; // Custom API parameters
|
42
|
-
|
43
|
-
this.upload_id = null; // The current upload ID
|
44
|
-
this.aborting = false; // Has the user has requested an abort?
|
45
|
-
this.xhr = null; // Any active cloud file xhr requests
|
46
|
-
};
|
47
|
-
|
48
|
-
|
49
|
-
// Inject the handlers
|
50
|
-
angular.forEach(residencies, function(value, key) {
|
51
|
-
residencies[key] = $injector.get(value);
|
52
|
-
});
|
53
|
-
|
54
|
-
|
55
|
-
$http.defaults.headers = {};
|
56
|
-
$http.defaults.headers['common'] = {'X-Requested-With': 'XMLHttpRequest'};
|
57
|
-
$http.defaults.headers['post'] = {'X-CSRF-Token': token};
|
58
|
-
$http.defaults.headers['put'] = {'X-CSRF-Token': token};
|
59
|
-
$http.defaults.headers['delete'] = {'X-CSRF-Token': token};
|
60
|
-
|
61
|
-
condoConnection.prototype = {
|
62
|
-
|
63
|
-
|
64
|
-
//
|
65
|
-
// Creates an entry in the database for the requested file and returns the upload signature
|
66
|
-
// If an entry already exists it returns a parts request signature for resumable uploads
|
67
|
-
//
|
68
|
-
create: function(options) { // file_id: 123, options: {}
|
69
|
-
var self = this;
|
70
|
-
options = options || {};
|
71
|
-
this.aborting = false;
|
72
|
-
|
73
|
-
if(!!options['file_id'])
|
74
|
-
this.params['file_id'] = options['file_id'];
|
75
|
-
|
76
|
-
if(!!options['parameters'])
|
77
|
-
this.params['parameters'] = options['parameters']; // We may be requesting the next set of parts
|
78
|
-
|
79
|
-
return $http({
|
80
|
-
method: 'POST',
|
81
|
-
url: this.endpoint,
|
82
|
-
params: this.params
|
83
|
-
}).then(function(result){
|
84
|
-
result = result.data;
|
85
|
-
self.upload_id = result.upload_id; // Extract the upload id from the results
|
86
|
-
|
87
|
-
if (!self.aborting)
|
88
|
-
return result;
|
89
|
-
else
|
90
|
-
return $q.reject(undefined);
|
91
|
-
}, function(reason) {
|
92
|
-
return $q.reject('upload error');
|
93
|
-
});
|
94
|
-
},
|
95
|
-
|
96
|
-
|
97
|
-
//
|
98
|
-
// This requests a chunk signature
|
99
|
-
// Only used for resumable uploads
|
100
|
-
//
|
101
|
-
edit: function(part_number, part_id) {
|
102
|
-
var self = this;
|
103
|
-
this.aborting = false;
|
104
|
-
|
105
|
-
return $http({
|
106
|
-
method: 'GET',
|
107
|
-
url: this.endpoint + '/' + this.upload_id + '/edit',
|
108
|
-
params: {
|
109
|
-
part: part_number,
|
110
|
-
file_id: part_id
|
111
|
-
}
|
112
|
-
}).then(function(result){
|
113
|
-
if (!self.aborting)
|
114
|
-
return result.data;
|
115
|
-
else
|
116
|
-
return $q.reject(undefined);
|
117
|
-
}, function(reason) {
|
118
|
-
return $q.reject('upload error');
|
119
|
-
});
|
120
|
-
},
|
121
|
-
|
122
|
-
|
123
|
-
//
|
124
|
-
// If resumable id is present the upload is updated
|
125
|
-
// Otherwise the upload deemed complete
|
126
|
-
//
|
127
|
-
update: function(params) { // optional parameters (resumable_id, file_id and part)
|
128
|
-
var self = this;
|
129
|
-
|
130
|
-
this.aborting = false;
|
131
|
-
params = params || {};
|
132
|
-
|
133
|
-
return $http({
|
134
|
-
method: 'PUT',
|
135
|
-
url: this.endpoint + '/' + this.upload_id,
|
136
|
-
params: params
|
137
|
-
}).then(function(result){
|
138
|
-
if (!self.aborting)
|
139
|
-
return result.data;
|
140
|
-
else
|
141
|
-
return $q.reject(undefined);
|
142
|
-
}, function(reason) {
|
143
|
-
if (reason.status == 401 && params.resumable_id == undefined) {
|
144
|
-
return ''; // User may have paused upload as put was being sent. We should let this through just to update the UI
|
145
|
-
} else
|
146
|
-
return $q.reject('upload error');
|
147
|
-
});
|
148
|
-
},
|
149
|
-
|
150
|
-
|
151
|
-
//
|
152
|
-
// Cancels a resumable upload
|
153
|
-
// The actual destruction of the file is handled on the server side as we can't trust the client to do this
|
154
|
-
// We don't care if this succeeds as the back-end will destroy the file eventually anyway.
|
155
|
-
//
|
156
|
-
destroy: function() {
|
157
|
-
return $http({
|
158
|
-
method: 'DELETE',
|
159
|
-
url: this.endpoint + '/' + this.upload_id
|
160
|
-
});
|
161
|
-
},
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
//
|
166
|
-
// Provides a promise for any request this is what communicated with the cloud storage servers
|
167
|
-
//
|
168
|
-
process_request: function(signature, progress_callback) {
|
169
|
-
var self = this,
|
170
|
-
result = $q.defer(),
|
171
|
-
params = {
|
172
|
-
url: signature.signature.url,
|
173
|
-
type: signature.signature.verb,
|
174
|
-
headers: signature.signature.headers,
|
175
|
-
processData: false,
|
176
|
-
success: function(response, textStatus, jqXHR) {
|
177
|
-
self.xhr = null;
|
178
|
-
result.resolve([response, jqXHR]);
|
179
|
-
},
|
180
|
-
error: function(jqXHR, textStatus, errorThrown) {
|
181
|
-
if(jqXHR.status === signature.expected) {
|
182
|
-
self.xhr = null;
|
183
|
-
result.resolve([errorThrown, jqXHR]);
|
184
|
-
} else {
|
185
|
-
self.xhr = null;
|
186
|
-
if (!self.aborting)
|
187
|
-
result.reject('upload error');
|
188
|
-
else
|
189
|
-
result.reject(undefined);
|
190
|
-
}
|
191
|
-
},
|
192
|
-
complete: function(jqXHR, textStatus) {
|
193
|
-
if(!$rootScope.$$phase) {
|
194
|
-
$rootScope.$apply(); // This triggers the promise response
|
195
|
-
}
|
196
|
-
}
|
197
|
-
};
|
198
|
-
|
199
|
-
this.aborting = false;
|
200
|
-
|
201
|
-
if (!!self.xhr) {
|
202
|
-
result.reject('request in progress'); // This is awesome
|
203
|
-
return result.promise;
|
204
|
-
}
|
205
|
-
|
206
|
-
if(!!signature.data){
|
207
|
-
params['data'] = signature.data;
|
208
|
-
}
|
209
|
-
|
210
|
-
if(!!progress_callback) {
|
211
|
-
params['xhr'] = function() {
|
212
|
-
var xhr = jQuery.ajaxSettings.xhr();
|
213
|
-
if(!!xhr.upload){
|
214
|
-
xhr.upload.addEventListener('progress', function(e) {
|
215
|
-
if (e.lengthComputable) {
|
216
|
-
var phase = $rootScope.$$phase;
|
217
|
-
if(phase == '$apply' || phase == '$digest') {
|
218
|
-
progress_callback(e.loaded);
|
219
|
-
} else {
|
220
|
-
$rootScope.$apply(function(){
|
221
|
-
progress_callback(e.loaded);
|
222
|
-
});
|
223
|
-
}
|
224
|
-
}
|
225
|
-
}, false);
|
226
|
-
}
|
227
|
-
return xhr;
|
228
|
-
};
|
229
|
-
}
|
230
|
-
|
231
|
-
this.xhr = jQuery.ajax(params);
|
232
|
-
|
233
|
-
return result.promise;
|
234
|
-
},
|
235
|
-
|
236
|
-
|
237
|
-
//
|
238
|
-
// Will trigger the error call-back of the xhr object
|
239
|
-
//
|
240
|
-
abort: function() {
|
241
|
-
this.aborting = true;
|
242
|
-
if(!!this.xhr) {
|
243
|
-
this.xhr.abort();
|
244
|
-
}
|
245
|
-
}
|
246
|
-
};
|
247
|
-
|
248
|
-
return {
|
249
|
-
//
|
250
|
-
// Used to determine what upload strategy to use (Amazon, Google, etc)
|
251
|
-
//
|
252
|
-
check_provider: function(api_endpoint, the_file, params) {
|
253
|
-
params = params || {};
|
254
|
-
params['file_size'] = the_file.size;
|
255
|
-
params['file_name'] = the_file.name;
|
256
|
-
|
257
|
-
if(!!the_file.dir_path)
|
258
|
-
params['file_path'] = the_file.dir_path;
|
259
|
-
|
260
|
-
return $http({
|
261
|
-
method: 'GET',
|
262
|
-
url: api_endpoint + '/new',
|
263
|
-
params: params
|
264
|
-
}).then(function(result){
|
265
|
-
if(!!residencies[result.data.residence]) {
|
266
|
-
|
267
|
-
var api = new condoConnection(api_endpoint, params);
|
268
|
-
|
269
|
-
//
|
270
|
-
// TODO:: Check if a file is already in the list and reject if it is
|
271
|
-
//
|
272
|
-
return residencies[result.data.residence].new_upload(api, the_file); // return the instantiated provider
|
273
|
-
|
274
|
-
} else {
|
275
|
-
return $q.reject({
|
276
|
-
type: 'error',
|
277
|
-
number: 0,
|
278
|
-
file: the_file
|
279
|
-
});
|
280
|
-
}
|
281
|
-
}, function(reason) {
|
282
|
-
if(reason.status == 406) {
|
283
|
-
return $q.reject({
|
284
|
-
type: 'warn',
|
285
|
-
number: 0,
|
286
|
-
details: reason.data,
|
287
|
-
file: the_file
|
288
|
-
});
|
289
|
-
} else {
|
290
|
-
return $q.reject({
|
291
|
-
type: 'warn',
|
292
|
-
number: 1,
|
293
|
-
file: the_file
|
294
|
-
});
|
295
|
-
}
|
296
|
-
});
|
297
|
-
}
|
298
|
-
};
|
299
|
-
}];
|
300
|
-
});
|
301
|
-
|
302
|
-
})(jQuery, angular);
|
@@ -1,17 +0,0 @@
|
|
1
|
-
|
2
|
-
(function(angular, undefined) {
|
3
|
-
'use strict';
|
4
|
-
|
5
|
-
angular.module('Core').
|
6
|
-
service('$safeApply', function() {
|
7
|
-
this.do = function(scope, fn) {
|
8
|
-
var phase = scope.$root.$$phase;
|
9
|
-
if(phase == '$apply' || phase == '$digest') {
|
10
|
-
fn();
|
11
|
-
} else {
|
12
|
-
scope.$apply(fn);
|
13
|
-
}
|
14
|
-
};
|
15
|
-
});
|
16
|
-
|
17
|
-
})(angular);
|
@@ -1,171 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* Core Messaging library
|
3
|
-
* Provides the core wrapper for application wide messaging and signalling
|
4
|
-
*
|
5
|
-
* Copyright (c) 2013 CoTag Media.
|
6
|
-
*
|
7
|
-
* @author Stephen von Takach <steve@cotag.me>
|
8
|
-
* @copyright 2013 cotag.me
|
9
|
-
*
|
10
|
-
*
|
11
|
-
* References:
|
12
|
-
* * http://www.gridlinked.info/angularJS/modules/MessagingServices.js
|
13
|
-
*
|
14
|
-
*
|
15
|
-
**/
|
16
|
-
|
17
|
-
(function(angular, undefined) {
|
18
|
-
'use strict';
|
19
|
-
|
20
|
-
angular.module('Core').
|
21
|
-
//
|
22
|
-
//
|
23
|
-
// Wrapper for jQuery Callbacks that provides a constructor for building
|
24
|
-
// application specific message channels
|
25
|
-
//
|
26
|
-
// e.g.
|
27
|
-
// factory('MyApp.Channel', ['Channel', function(Channel) {
|
28
|
-
// return Channel.openChannel('once memory unique stopOnFalse'); // settings are optional
|
29
|
-
// }]);
|
30
|
-
//
|
31
|
-
// then in a controller / directive somewhere:
|
32
|
-
// controller('MyApp.Cntrl', ['$scope', 'MyApp.Channel', function($scope, channel) {
|
33
|
-
// channel.subscribe(function(value) { $scope.update = value; });
|
34
|
-
// }
|
35
|
-
//
|
36
|
-
//
|
37
|
-
factory('$channel', ['$rootScope', '$safeApply', function($rootScope, safeApply) {
|
38
|
-
var getChannel = function(settings) {
|
39
|
-
var callback = angular.element.Callbacks(settings);
|
40
|
-
return {
|
41
|
-
publish: function() {
|
42
|
-
var args = arguments; // Curry the arguments
|
43
|
-
safeApply.do($rootScope, function() {
|
44
|
-
callback.fire.apply(callback, args);
|
45
|
-
});
|
46
|
-
},
|
47
|
-
subscribe: callback.add,
|
48
|
-
unsubscribe: callback.remove,
|
49
|
-
has: callback.has,
|
50
|
-
empty: callback.empty
|
51
|
-
};
|
52
|
-
};
|
53
|
-
|
54
|
-
return {
|
55
|
-
openChannel: getChannel
|
56
|
-
};
|
57
|
-
}]).
|
58
|
-
|
59
|
-
|
60
|
-
//
|
61
|
-
//
|
62
|
-
// Wrapper for jQuery Callbacks that provides a constructor for building
|
63
|
-
// application specific messaging factories
|
64
|
-
//
|
65
|
-
// e.g.
|
66
|
-
// factory('MyApp.Messenger', ['Spectrum', function(Spectrum) {
|
67
|
-
// return Spectrum.newSpectrum('once memory unique stopOnFalse'); // settings are optional
|
68
|
-
// }]);
|
69
|
-
//
|
70
|
-
// then in a controller / directive somewhere:
|
71
|
-
// controller('MyApp.Cntrl', ['$scope', 'MyApp.Messenger', function($scope, messages) {
|
72
|
-
// var channel = messages.openChannel('controllers');
|
73
|
-
// channel.subscribe(function(value) { $scope.update = value; });
|
74
|
-
// }
|
75
|
-
//
|
76
|
-
//
|
77
|
-
factory('$spectrum', ['$channel', function(Channel) {
|
78
|
-
|
79
|
-
var buildSpectrum = function(settings) {
|
80
|
-
var channels = {},
|
81
|
-
|
82
|
-
//
|
83
|
-
// Creates or returns a reference to a channel in the spectrum
|
84
|
-
//
|
85
|
-
openChannel = function(name) {
|
86
|
-
var channel = name && channels[name],
|
87
|
-
callback;
|
88
|
-
|
89
|
-
if (!channel) {
|
90
|
-
channel = {
|
91
|
-
access: Channel.openChannel(settings),
|
92
|
-
count: 0
|
93
|
-
};
|
94
|
-
|
95
|
-
channels[name] = channel;
|
96
|
-
}
|
97
|
-
|
98
|
-
return channel;
|
99
|
-
}, // end openChannel
|
100
|
-
|
101
|
-
//
|
102
|
-
// Deletes channels that are no longer in use
|
103
|
-
//
|
104
|
-
closeChannel = function(name) {
|
105
|
-
delete channels[name];
|
106
|
-
return 0;
|
107
|
-
},
|
108
|
-
|
109
|
-
channelList = function() {
|
110
|
-
return Object.keys(channels);
|
111
|
-
},
|
112
|
-
|
113
|
-
subscribeTo = function(name, callback) {
|
114
|
-
var channel = channels[name] || openChannel(name);
|
115
|
-
if(!channel.access.has(callback)) {
|
116
|
-
channel.access.subscribe(callback);
|
117
|
-
channel.count += 1;
|
118
|
-
}
|
119
|
-
return channel.count;
|
120
|
-
},
|
121
|
-
|
122
|
-
subscribedTo = function(name) {
|
123
|
-
return !channels[name] ? 0 : channels[name].count;
|
124
|
-
},
|
125
|
-
|
126
|
-
unsubscribeFrom = function(name, callback) {
|
127
|
-
var channel = channels[name];
|
128
|
-
|
129
|
-
if (!!channel) {
|
130
|
-
if(callback === undefined) {
|
131
|
-
return closeChannel(name);
|
132
|
-
} else if (channel.access.has(callback)) {
|
133
|
-
if (channel.count > 1) {
|
134
|
-
channel.access.unsubscribe(callback);
|
135
|
-
channel.count -= 1;
|
136
|
-
} else {
|
137
|
-
return closeChannel(name);
|
138
|
-
}
|
139
|
-
}
|
140
|
-
return channel.count;
|
141
|
-
}
|
142
|
-
return 0;
|
143
|
-
},
|
144
|
-
|
145
|
-
publishTo = function(name) {
|
146
|
-
var channel = channels[name];
|
147
|
-
|
148
|
-
if (!!channel) {
|
149
|
-
channel.access.publish.apply(channel.access, Array.prototype.slice.call( arguments, 1 ));
|
150
|
-
} else if (settings.match(/memory/i)) {
|
151
|
-
channel = openChannel(name);
|
152
|
-
channel.access.publish.apply(channel.access, Array.prototype.slice.call( arguments, 1 ));
|
153
|
-
}
|
154
|
-
};
|
155
|
-
|
156
|
-
return {
|
157
|
-
channelList: channelList,
|
158
|
-
subscribe: subscribeTo,
|
159
|
-
subscriptions: subscribedTo,
|
160
|
-
unsubscribe: unsubscribeFrom,
|
161
|
-
publish: publishTo
|
162
|
-
};
|
163
|
-
}; // End buildSpectrum
|
164
|
-
|
165
|
-
return {
|
166
|
-
newSpectrum: buildSpectrum
|
167
|
-
};
|
168
|
-
}]);
|
169
|
-
|
170
|
-
|
171
|
-
})(angular);
|