condo 1.0.4 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
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