condo 1.0.4 → 1.0.6

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.
Files changed (32) hide show
  1. checksums.yaml +7 -0
  2. data/README.textile +133 -133
  3. data/app/assets/javascripts/condo.js +9 -6
  4. data/app/assets/javascripts/condo/amazon.js +403 -406
  5. data/app/assets/javascripts/condo/condo.js +184 -0
  6. data/app/assets/javascripts/condo/config.js +69 -80
  7. data/app/assets/javascripts/condo/google.js +338 -255
  8. data/app/assets/javascripts/condo/md5/hash.worker.emulator.js +23 -23
  9. data/app/assets/javascripts/condo/md5/hash.worker.js +11 -11
  10. data/app/assets/javascripts/condo/md5/hasher.js +119 -100
  11. data/app/assets/javascripts/condo/md5/spark-md5.js +276 -161
  12. data/app/assets/javascripts/condo/rackspace.js +326 -329
  13. data/app/assets/javascripts/condo/{abstract-md5.js.erb → services/abstract-md5.js.erb} +86 -93
  14. data/app/assets/javascripts/condo/{base64.js → services/base64.js} +2 -10
  15. data/app/assets/javascripts/condo/services/broadcaster.js +26 -0
  16. data/app/assets/javascripts/condo/services/uploader.js +302 -0
  17. data/app/assets/javascripts/core/core.js +4 -0
  18. data/app/assets/javascripts/core/services/1-safe-apply.js +17 -0
  19. data/app/assets/javascripts/core/services/2-messaging.js +171 -0
  20. data/lib/condo.rb +269 -269
  21. data/lib/condo/configuration.rb +137 -139
  22. data/lib/condo/errors.rb +8 -8
  23. data/lib/condo/strata/amazon_s3.rb +301 -301
  24. data/lib/condo/strata/google_cloud_storage.rb +315 -314
  25. data/lib/condo/strata/rackspace_cloud_files.rb +245 -223
  26. data/lib/condo/version.rb +1 -1
  27. metadata +21 -44
  28. data/app/assets/javascripts/condo/broadcaster.js +0 -60
  29. data/app/assets/javascripts/condo/controller.js +0 -194
  30. data/app/assets/javascripts/condo/uploader.js +0 -310
  31. data/test/dummy/db/test.sqlite3 +0 -0
  32. data/test/dummy/log/test.log +0 -25
@@ -0,0 +1,4 @@
1
+ //
2
+ // Defines our core module
3
+ //
4
+ angular.module('Core', []);
@@ -0,0 +1,17 @@
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);
@@ -0,0 +1,171 @@
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);
@@ -1,269 +1,269 @@
1
- require 'condo/engine'
2
- require 'condo/errors'
3
- require 'condo/configuration'
4
-
5
-
6
- #Dir[File.join('condo', 'strata', '*.rb')].each do |file| # Using autoload_paths now
7
- # require file[0..-4] # Removes the .rb ext name
8
- #end
9
-
10
-
11
- module Condo
12
-
13
- #
14
- # TODO:: Simplify the parameters passed in
15
- # Object options should be set at the application level
16
- # The application can set these based on the custom params.
17
- # Have an instance member that holds the parameter set: @upload
18
- #
19
- def self.included(base)
20
- base.class_eval do
21
-
22
-
23
- def new
24
- #
25
- # Returns the provider that will be used for this file upload
26
- #
27
- resident = current_resident
28
-
29
- @upload ||= {}
30
- @upload[:file_size] = params[:file_size].to_i
31
- @upload[:file_name] = (instance_eval &@@callbacks[:sanitize_filename])
32
- @upload[:file_path] = (instance_eval &@@callbacks[:sanitize_filepath]) if params[:file_path]
33
-
34
- valid, errors = instance_eval &@@callbacks[:pre_validation] # Ensure the upload request is valid before uploading
35
-
36
- if !!valid
37
- set_residence(nil, {:resident => resident, :params => @upload}) if condo_config.dynamic_provider_present?(@@namespace)
38
- residence = current_residence
39
-
40
- render :json => {:residence => residence.name}
41
-
42
- elsif errors.is_a? Hash
43
- render :json => errors, :status => :not_acceptable
44
- else
45
- render :nothing => true, :status => :not_acceptable
46
- end
47
- end
48
-
49
- def create
50
- #
51
- # Check for existing upload or create a new one
52
- # => mutually exclusive so can send back either the parts signature from show or a bucket creation signature and the upload_id
53
- #
54
- resident = current_resident
55
-
56
- @upload = {}
57
- @upload[:file_size] = params[:file_size].to_i
58
- @upload[:file_id] = params[:file_id]
59
- @upload[:file_name] = (instance_eval &@@callbacks[:sanitize_filename])
60
- @upload[:file_path] = (instance_eval &@@callbacks[:sanitize_filepath]) if params[:file_path]
61
-
62
- upload = condo_backend.check_exists({
63
- :user_id => resident,
64
- :file_name => @upload[:file_name],
65
- :file_size => @upload[:file_size],
66
- :file_id => @upload[:file_id]
67
- })
68
-
69
- if upload.present?
70
- residence = set_residence(upload.provider_name, {
71
- :location => upload.provider_location,
72
- :upload => upload
73
- })
74
-
75
- #
76
- # Return the parts or direct upload sig
77
- #
78
- request = nil
79
- if upload.resumable_id.present? && upload.resumable
80
- upload.object_options[:parameters] = {} || params[:parameters] # May need to request the next set of parts
81
- request = residence.get_parts({
82
- :bucket_name => upload.bucket_name,
83
- :object_key => upload.object_key,
84
- :object_options => upload.object_options,
85
- :resumable_id => upload.resumable_id
86
- })
87
- else
88
- request = residence.new_upload({
89
- :bucket_name => upload.bucket_name,
90
- :object_key => upload.object_key,
91
- :object_options => upload.object_options,
92
- :file_size => upload.file_size,
93
- :file_id => upload.file_id
94
- })
95
- end
96
-
97
- render :json => request.merge(:upload_id => upload.id, :residence => residence.name)
98
- else
99
- #
100
- # Create a new upload
101
- #
102
- valid, errors = instance_eval &@@callbacks[:pre_validation] # Ensure the upload request is valid before uploading
103
-
104
-
105
- if !!valid
106
- set_residence(nil, {:resident => resident, :params => @upload}) if condo_config.dynamic_provider_present?(@@namespace)
107
- residence = current_residence
108
-
109
- #
110
- # Build the request
111
- #
112
- request = residence.new_upload(@upload.merge!({
113
- :bucket_name => (instance_eval &@@callbacks[:bucket_name]), # Allow the application to define a custom bucket name
114
- :object_key => (instance_eval &@@callbacks[:object_key]), # The object key should also be generated by the application
115
- :object_options => (instance_eval &@@callbacks[:object_options]) # Do we want to mess with any of the options?
116
- }))
117
- resumable = request[:type] == :chunked_upload
118
-
119
- #
120
- # Save a reference to this upload in the database
121
- # => This should throw an error on failure
122
- #
123
- upload = condo_backend.add_entry(@upload.merge!({:user_id => resident, :provider_name => residence.name, :provider_location => residence.location, :resumable => resumable}))
124
- render :json => request.merge!(:upload_id => upload.id, :residence => residence.name)
125
-
126
- elsif errors.is_a? Hash
127
- render :json => errors, :status => :not_acceptable
128
- else
129
- render :nothing => true, :status => :not_acceptable
130
- end
131
- end
132
- end
133
-
134
-
135
- #
136
- # Authorisation check all of these
137
- #
138
- def edit
139
- #
140
- # Get the signature for parts + final commit
141
- #
142
- upload = current_upload
143
-
144
- if upload.resumable_id.present? && upload.resumable
145
- residence = set_residence(upload.provider_name, {:location => upload.provider_location, :upload => upload})
146
-
147
- request = residence.set_part({
148
- :bucket_name => upload.bucket_name,
149
- :object_key => upload.object_key,
150
- :object_options => upload.object_options,
151
- :resumable_id => upload.resumable_id,
152
- :part => params[:part], # part may be called 'finish' for commit signature
153
- :file_id => params[:file_id]
154
- })
155
-
156
- render :json => request.merge!(:upload_id => upload.id)
157
- else
158
- render :nothing => true, :status => :not_acceptable
159
- end
160
- end
161
-
162
-
163
- def update
164
- #
165
- # Provide the upload id after creating a resumable upload (may not be completed)
166
- # => We then provide the first part signature
167
- #
168
- # OR
169
- #
170
- # Complete an upload
171
- #
172
- if params[:resumable_id]
173
- upload = current_upload
174
- if upload.resumable
175
- @current_upload = upload.update_entry :resumable_id => params[:resumable_id]
176
- edit
177
- else
178
- render :nothing => true, :status => :not_acceptable
179
- end
180
- else
181
- response = instance_exec current_upload, &@@callbacks[:upload_complete]
182
- if !!response
183
- current_upload.remove_entry
184
- render :nothing => true
185
- else
186
- render :nothing => true, :status => :not_acceptable
187
- end
188
- end
189
- end
190
-
191
-
192
- def destroy
193
- #
194
- # Delete the file from the cloud system - the client is not responsible for this
195
- #
196
- response = instance_exec current_upload, &@@callbacks[:destroy_upload]
197
- if !!response
198
- current_upload.remove_entry
199
- render :nothing => true
200
- else
201
- render :nothing => true, :status => :not_acceptable
202
- end
203
- end
204
-
205
-
206
- protected
207
-
208
-
209
- #
210
- # A before filter can be used to select the cloud provider for the current user
211
- # Otherwise the dynamic residence can be used when users are define their own storage locations
212
- #
213
- def set_residence(name, options = {})
214
- options[:namespace] = @@namespace
215
- @current_residence = condo_config.set_residence(name, options)
216
- end
217
-
218
- def current_residence
219
- @current_residence ||= condo_config.residencies[0]
220
- end
221
-
222
- def current_upload
223
- @current_upload ||= condo_backend.check_exists({:user_id => current_resident, :upload_id => (params[:upload_id] || params[:id])}).tap do |object| #current_residence.name && current_residence.location && resident.id.exists?
224
- raise Condo::Errors::NotYourPlace unless object.present?
225
- end
226
- end
227
-
228
- def current_resident
229
- @current_resident ||= (instance_eval &@@callbacks[:resident_id]).tap do |object| # instance_exec for params
230
- raise Condo::Errors::LostTheKeys unless object.present?
231
- end
232
- end
233
-
234
- def condo_backend
235
- Condo::Store
236
- end
237
-
238
- def condo_config
239
- Condo::Configuration.instance
240
- end
241
-
242
-
243
- #
244
- # Defines the default callbacks
245
- #
246
- (@@callbacks ||= {}).merge! Condo::Configuration.callbacks
247
- @@namespace ||= :global
248
-
249
-
250
- def self.set_callback(name, callback = nil, &block)
251
- if callback.is_a?(Proc)
252
- @@callbacks[name.to_sym] = callback
253
- elsif block.present?
254
- @@callbacks[name.to_sym] = block
255
- else
256
- raise ArgumentError, 'Condo callbacks must be defined with a Proc or Proc (lamba) object present'
257
- end
258
- end
259
-
260
-
261
- def self.set_namespace(name)
262
- @@namespace = name.to_sym
263
- end
264
-
265
- end
266
- end
267
-
268
-
269
- end
1
+ require 'condo/engine'
2
+ require 'condo/errors'
3
+ require 'condo/configuration'
4
+
5
+
6
+ module Condo
7
+ def self.included(base)
8
+ base.class_eval do
9
+
10
+
11
+ def new
12
+ #
13
+ # Returns the provider that will be used for this file upload
14
+ resident = current_resident
15
+
16
+ #
17
+ # Ensure parameters are correct
18
+ params.require(:file_size)
19
+ params.require(:file_name)
20
+ permitted = params.permit(:file_size, :file_name, :file_path)
21
+ @upload = {
22
+ file_size: permitted[:file_size].to_i,
23
+ file_name: @@callbacks[:sanitize_filename].call(permitted[:file_name])
24
+ }
25
+ @upload[:file_path] = @@callbacks[:sanitize_filepath].call(permitted[:file_path]) if permitted[:file_path]
26
+
27
+ valid, errors = instance_exec(@upload, &@@callbacks[:pre_validation]) # Ensure the upload request is valid before uploading
28
+
29
+ if !!valid
30
+ set_residence(nil, {:resident => resident, :params => @upload}) if condo_config.dynamic_provider_present?(@@namespace)
31
+ residence = current_residence
32
+
33
+ render :json => {:residence => residence.name}
34
+
35
+ elsif errors.is_a? Hash
36
+ render :json => errors, :status => :not_acceptable
37
+ else
38
+ render :nothing => true, :status => :not_acceptable
39
+ end
40
+ end
41
+
42
+ def create
43
+ #
44
+ # Check for existing upload or create a new one
45
+ # => mutually exclusive so can send back either the parts signature from show or a bucket creation signature and the upload_id
46
+ #
47
+ resident = current_resident
48
+
49
+ #
50
+ # Ensure parameters are correct
51
+ params.require(:file_size)
52
+ params.require(:file_name)
53
+ params.require(:file_id)
54
+ permitted = params.permit(:file_size, :file_name, :file_path, :file_id)
55
+ @upload = {
56
+ file_size: permitted[:file_size].to_i,
57
+ file_name: @@callbacks[:sanitize_filename].call(permitted[:file_name]),
58
+ file_id: permitted[:file_id],
59
+ user_id: resident
60
+ }
61
+ @upload[:file_path] = @@callbacks[:sanitize_filepath].call(permitted[:file_path]) if permitted[:file_path]
62
+
63
+ #
64
+ # Check for existing uploads
65
+ upload = condo_backend.check_exists(@upload)
66
+
67
+ if upload.present?
68
+ residence = set_residence(upload.provider_name, {
69
+ :location => upload.provider_location,
70
+ :upload => upload
71
+ })
72
+
73
+ #
74
+ # Return the parts or direct upload sig
75
+ #
76
+ request = nil
77
+ if upload.resumable_id.present? && upload.resumable
78
+ request = residence.get_parts({
79
+ :bucket_name => upload.bucket_name,
80
+ :object_key => upload.object_key,
81
+ :object_options => upload.object_options,
82
+ :file_size => upload.file_size,
83
+ :resumable_id => upload.resumable_id
84
+ })
85
+ else
86
+ request = residence.new_upload({
87
+ :bucket_name => upload.bucket_name,
88
+ :object_key => upload.object_key,
89
+ :object_options => upload.object_options,
90
+ :file_size => upload.file_size,
91
+ :file_id => upload.file_id
92
+ })
93
+ end
94
+
95
+ render :json => request.merge(:upload_id => upload.id, :residence => residence.name)
96
+ else
97
+ #
98
+ # Create a new upload
99
+ #
100
+ valid, errors = instance_exec(@upload, &@@callbacks[:pre_validation]) # Ensure the upload request is valid before uploading
101
+
102
+
103
+ if valid
104
+ set_residence(nil, {:resident => resident, :params => @upload}) if condo_config.dynamic_provider_present?(@@namespace)
105
+ residence = current_residence
106
+
107
+ #
108
+ # Build the request
109
+ #
110
+ @upload.merge!({
111
+ bucket_name: (instance_eval &@@callbacks[:bucket_name]), # Allow the application to define a custom bucket name
112
+ object_key: instance_exec(@upload, &@@callbacks[:object_key]), # The object key should also be generated by the application
113
+ object_options: instance_exec(@upload, &@@callbacks[:object_options]) # Do we want to mess with any of the options?
114
+ })
115
+ request = residence.new_upload(@upload)
116
+ resumable = request[:type] == :chunked_upload
117
+
118
+ #
119
+ # Save a reference to this upload in the database
120
+ # => This should throw an error on failure
121
+ #
122
+ upload = condo_backend.add_entry(@upload.merge!({:provider_name => residence.name, :provider_location => residence.location, :resumable => resumable}))
123
+ render :json => request.merge!(:upload_id => upload.id, :residence => residence.name)
124
+
125
+ elsif errors.is_a? Hash
126
+ render :json => errors, :status => :not_acceptable
127
+ else
128
+ render :nothing => true, :status => :not_acceptable
129
+ end
130
+ end
131
+ end
132
+
133
+
134
+ #
135
+ # Authorization check all of these
136
+ #
137
+ def edit
138
+ #
139
+ # Get the signature for parts + final commit
140
+ #
141
+ upload = current_upload
142
+ params.require(:part)
143
+ safe_params = params.permit(:part, :file_id)
144
+
145
+ if upload.resumable_id.present? && upload.resumable
146
+ residence = set_residence(upload.provider_name, {:location => upload.provider_location, :upload => upload})
147
+
148
+ request = residence.set_part({
149
+ :bucket_name => upload.bucket_name,
150
+ :object_key => upload.object_key,
151
+ :object_options => upload.object_options,
152
+ :resumable_id => upload.resumable_id,
153
+ :part => safe_params[:part], # part may be called 'finish' for commit signature
154
+ :file_size => upload.file_size,
155
+ :file_id => safe_params[:file_id]
156
+ })
157
+
158
+ render :json => request.merge!(:upload_id => upload.id)
159
+ else
160
+ render :nothing => true, :status => :not_acceptable
161
+ end
162
+ end
163
+
164
+
165
+ def update
166
+ #
167
+ # Provide the upload id after creating a resumable upload (may not be completed)
168
+ # => We then provide the first part signature
169
+ #
170
+ # OR
171
+ #
172
+ # Complete an upload
173
+ #
174
+ if params[:resumable_id]
175
+ upload = current_upload
176
+ if upload.resumable
177
+ @current_upload = upload.update_entry :resumable_id => params.permit(:resumable_id)[:resumable_id]
178
+ edit
179
+ else
180
+ render :nothing => true, :status => :not_acceptable
181
+ end
182
+ else
183
+ response = instance_exec current_upload, &@@callbacks[:upload_complete]
184
+ if response
185
+ render :nothing => true
186
+ else
187
+ render :nothing => true, :status => :not_acceptable
188
+ end
189
+ end
190
+ end
191
+
192
+
193
+ def destroy
194
+ #
195
+ # Delete the file from the cloud system - the client is not responsible for this
196
+ #
197
+ response = instance_exec current_upload, &@@callbacks[:destroy_upload]
198
+ if response
199
+ render :nothing => true
200
+ else
201
+ render :nothing => true, :status => :not_acceptable
202
+ end
203
+ end
204
+
205
+
206
+ protected
207
+
208
+
209
+ #
210
+ # A before filter can be used to select the cloud provider for the current user
211
+ # Otherwise the dynamic residence can be used when users are define their own storage locations
212
+ #
213
+ def set_residence(name, options = {})
214
+ options[:namespace] = @@namespace
215
+ @current_residence = condo_config.set_residence(name, options)
216
+ end
217
+
218
+ def current_residence
219
+ @current_residence ||= condo_config.residencies[0]
220
+ end
221
+
222
+ def current_upload
223
+ return @current_upload if @current_upload
224
+
225
+ safe_params = params.permit(:upload_id, :id)
226
+ @current_upload = condo_backend.check_exists({:user_id => current_resident, :upload_id => (safe_params[:upload_id] || safe_params[:id])}).tap do |object| #current_residence.name && current_residence.location && resident.id.exists?
227
+ raise Condo::Errors::NotYourPlace unless object.present?
228
+ end
229
+ end
230
+
231
+ def current_resident
232
+ @current_resident ||= (instance_eval &@@callbacks[:resident_id]).tap do |object| # instance_exec for params
233
+ raise Condo::Errors::LostTheKeys unless object.present?
234
+ end
235
+ end
236
+
237
+ def condo_backend
238
+ Condo::Store
239
+ end
240
+
241
+ def condo_config
242
+ Condo::Configuration.instance
243
+ end
244
+
245
+
246
+ #
247
+ # Defines the default callbacks
248
+ #
249
+ (@@callbacks ||= {}).merge! Condo::Configuration.callbacks
250
+ @@namespace ||= :global
251
+
252
+
253
+ def self.condo_callback(name, callback = nil, &block)
254
+ callback ||= block
255
+ if callback.respond_to?(:call)
256
+ @@callbacks[name.to_sym] = callback
257
+ else
258
+ raise ArgumentError, 'No callback provided'
259
+ end
260
+ end
261
+
262
+
263
+ def self.condo_namespace(name)
264
+ @@namespace = name.to_sym
265
+ end
266
+
267
+ end
268
+ end
269
+ end