condo 1.0.6 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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);
|