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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 92cc7003ecce7499b7c92bc3aed7facde40cf79d
|
4
|
+
data.tar.gz: a4b4e8d9a93bace70e3c236d13d23d97116dd44e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c45dcf3f6aed9abe71705db52d83ffd3731c105259d10d43672f2deff33d2e19bcb6e3d7e77a7b47e373ef882ddf3ffc9949661363460a103f25356787e402cc
|
7
|
+
data.tar.gz: bbd682e45ad4a9f651d77abd5cae57e14b163ca476d38cc89c78ff8b3678c35ab37a9c6df36a601e2f28339a605ff67958a2bef7faf82d59f661aad6a6ba3ebd
|
data/README.textile
CHANGED
@@ -3,6 +3,7 @@ h1. Condominios aka Condo
|
|
3
3
|
A "Rails plugin":http://guides.rubyonrails.org/plugins.html and "AngularJS application":http://angularjs.org/ that makes direct uploads to multiple cloud storage providers easy.
|
4
4
|
Only supports "XMLHttpRequest Level 2":http://en.wikipedia.org/wiki/XMLHttpRequest capable browsers and cloud providers that have a "RESTful API":http://en.wikipedia.org/wiki/Representational_state_transfer with "CORS":http://en.wikipedia.org/wiki/Cross-origin_resource_sharing support.
|
5
5
|
|
6
|
+
|
6
7
|
Why compromise?
|
7
8
|
|
8
9
|
Get started now: @gem install condo@ or checkout the "example application":https://github.com/cotag/condo_example
|
@@ -22,18 +23,23 @@ The API is RESTful, providing an abstraction layer and signed URLs that can be u
|
|
22
23
|
The main advantages are:
|
23
24
|
* Off-loads processing to client machines
|
24
25
|
* Better guarantees against upload corruption
|
25
|
-
** file hashing on the client side
|
26
|
-
* Upload results are guaranteed
|
26
|
+
** file hashing on the client side
|
27
|
+
* Upload results are guaranteed
|
27
28
|
** user is always aware of any failures in the process
|
28
29
|
* Detailed progress and control over the upload
|
29
30
|
|
30
31
|
This has numerous advantages over traditional Form Data style post uploads too.
|
31
32
|
* Progress bars
|
32
33
|
* Resumability when uploading large files
|
34
|
+
* Optional parallel uploads (multiple parts of the file simultaneously)
|
33
35
|
|
34
36
|
|
35
37
|
Support for all major browsers
|
36
|
-
*
|
38
|
+
* Chrome
|
39
|
+
* Firefox
|
40
|
+
* Safari
|
41
|
+
* Opera
|
42
|
+
* IE10+
|
37
43
|
|
38
44
|
|
39
45
|
h2. Usage
|
@@ -88,12 +94,11 @@ In an initialiser do the following:
|
|
88
94
|
|
89
95
|
<pre><code class="ruby">
|
90
96
|
Condo::Configuration.add_residence(:AmazonS3, {
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
# Controller must have the following line 'set_namespace :admin_resident'
|
97
|
+
:access_id => ENV['S3_KEY'],
|
98
|
+
:secret_key => ENV['S3_SECRET']
|
99
|
+
# :location => 'us-west-1' # or 'ap-southeast-1' etc (see http://docs.amazonwebservices.com/general/latest/gr/rande.html#s3_region)
|
100
|
+
# Defaults to 'us-east-1' or US Standard - not required for Google
|
101
|
+
# :namespace => :admin_resident # Allows you to assign different defaults to different controllers or users etc
|
97
102
|
})
|
98
103
|
|
99
104
|
</code></pre>
|
@@ -102,32 +107,14 @@ The first residence to be defined in a namespace will be the default. To change
|
|
102
107
|
Currently available residencies:
|
103
108
|
* :AmazonS3
|
104
109
|
* :GoogleCloudStorage
|
105
|
-
* :RackspaceCloudFiles
|
106
|
-
|
110
|
+
* :RackspaceCloudFiles (Works with Swift left as rackspace for backwards compatibility)
|
107
111
|
|
108
|
-
You can also define a dynamic residence each request (maybe clients provided you with access information for their storage provider)
|
109
112
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
:secret_key => user.s3_secret,
|
114
|
-
:dynamic => true # Otherwise the same as add_residence
|
115
|
-
});
|
116
|
-
|
117
|
-
|
118
|
-
</code></pre>
|
113
|
+
Note:: There is also a callback to dynamically set storage provider. Which is useful if your users use:
|
114
|
+
* Their own bucket
|
115
|
+
* Different cloud providers etc
|
119
116
|
|
120
117
|
|
121
118
|
h3. Callbacks
|
122
119
|
|
123
|
-
These are pretty well defined "here":https://github.com/cotag/
|
124
|
-
|
125
|
-
|
126
|
-
h2. TODO::
|
127
|
-
|
128
|
-
# Write tests... So many tests
|
129
|
-
# Create a wiki describing things in more detail
|
130
|
-
# Implement API for more residencies
|
131
|
-
# Sign other useful requests (bucket listings with search etc)
|
132
|
-
#* For Dropbox or Megaupload style applications
|
133
|
-
|
120
|
+
These are pretty well defined "here":https://github.com/cotag/Condominios/blob/master/lib/condo/configuration.rb
|
data/lib/condo.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'fog'
|
1
4
|
require 'condo/engine'
|
2
5
|
require 'condo/errors'
|
3
6
|
require 'condo/configuration'
|
@@ -6,14 +9,12 @@ require 'condo/configuration'
|
|
6
9
|
module Condo
|
7
10
|
def self.included(base)
|
8
11
|
base.class_eval do
|
9
|
-
|
10
|
-
|
12
|
+
|
13
|
+
|
11
14
|
def new
|
12
|
-
#
|
13
15
|
# Returns the provider that will be used for this file upload
|
14
16
|
resident = current_resident
|
15
17
|
|
16
|
-
#
|
17
18
|
# Ensure parameters are correct
|
18
19
|
params.require(:file_size)
|
19
20
|
params.require(:file_name)
|
@@ -23,30 +24,25 @@ module Condo
|
|
23
24
|
file_name: @@callbacks[:sanitize_filename].call(permitted[:file_name])
|
24
25
|
}
|
25
26
|
@upload[:file_path] = @@callbacks[:sanitize_filepath].call(permitted[:file_path]) if permitted[:file_path]
|
26
|
-
|
27
|
+
|
27
28
|
valid, errors = instance_exec(@upload, &@@callbacks[:pre_validation]) # Ensure the upload request is valid before uploading
|
28
29
|
|
29
|
-
if
|
30
|
-
set_residence(nil, {:resident => resident, :params => @upload}) if condo_config.dynamic_provider_present?(@@namespace)
|
30
|
+
if valid
|
31
31
|
residence = current_residence
|
32
|
-
|
33
|
-
render :
|
34
|
-
|
32
|
+
|
33
|
+
render json: {residence: residence.name}
|
35
34
|
elsif errors.is_a? Hash
|
36
|
-
render :
|
35
|
+
render json: errors, status: :not_acceptable
|
37
36
|
else
|
38
|
-
render :
|
37
|
+
render nothing: true, status: :not_acceptable
|
39
38
|
end
|
40
39
|
end
|
41
|
-
|
40
|
+
|
42
41
|
def create
|
43
|
-
#
|
44
42
|
# Check for existing upload or create a new one
|
45
43
|
# => mutually exclusive so can send back either the parts signature from show or a bucket creation signature and the upload_id
|
46
|
-
#
|
47
44
|
resident = current_resident
|
48
|
-
|
49
|
-
#
|
45
|
+
|
50
46
|
# Ensure parameters are correct
|
51
47
|
params.require(:file_size)
|
52
48
|
params.require(:file_name)
|
@@ -59,54 +55,48 @@ module Condo
|
|
59
55
|
user_id: resident
|
60
56
|
}
|
61
57
|
@upload[:file_path] = @@callbacks[:sanitize_filepath].call(permitted[:file_path]) if permitted[:file_path]
|
62
|
-
|
63
|
-
#
|
58
|
+
|
64
59
|
# Check for existing uploads
|
65
60
|
upload = condo_backend.check_exists(@upload)
|
66
|
-
|
61
|
+
|
67
62
|
if upload.present?
|
68
|
-
residence =
|
69
|
-
|
70
|
-
:upload => upload
|
71
|
-
})
|
72
|
-
|
73
|
-
#
|
63
|
+
residence = current_residence(upload)
|
64
|
+
|
74
65
|
# Return the parts or direct upload sig
|
75
|
-
#
|
76
66
|
request = nil
|
77
67
|
if upload.resumable_id.present? && upload.resumable
|
78
68
|
request = residence.get_parts({
|
79
|
-
:
|
80
|
-
:
|
81
|
-
:
|
82
|
-
:
|
83
|
-
:
|
69
|
+
bucket_name: upload.bucket_name,
|
70
|
+
object_key: upload.object_key,
|
71
|
+
object_options: upload.object_options,
|
72
|
+
file_size: upload.file_size,
|
73
|
+
resumable_id: upload.resumable_id
|
84
74
|
})
|
75
|
+
|
76
|
+
request[:part_list] = upload.part_list || []
|
77
|
+
request[:part_data] = upload.part_data if upload.part_data
|
85
78
|
else
|
86
79
|
request = residence.new_upload({
|
87
|
-
:
|
88
|
-
:
|
89
|
-
:
|
90
|
-
:
|
91
|
-
:
|
80
|
+
bucket_name: upload.bucket_name,
|
81
|
+
object_key: upload.object_key,
|
82
|
+
object_options: upload.object_options,
|
83
|
+
file_size: upload.file_size,
|
84
|
+
file_id: upload.file_id
|
92
85
|
})
|
93
86
|
end
|
94
87
|
|
95
|
-
render :
|
88
|
+
render json: request.merge!({
|
89
|
+
upload_id: upload.id,
|
90
|
+
residence: residence.name
|
91
|
+
})
|
96
92
|
else
|
97
|
-
#
|
98
93
|
# Create a new upload
|
99
|
-
#
|
100
94
|
valid, errors = instance_exec(@upload, &@@callbacks[:pre_validation]) # Ensure the upload request is valid before uploading
|
101
|
-
|
102
|
-
|
95
|
+
|
103
96
|
if valid
|
104
|
-
set_residence(nil, {:resident => resident, :params => @upload}) if condo_config.dynamic_provider_present?(@@namespace)
|
105
97
|
residence = current_residence
|
106
|
-
|
107
|
-
#
|
98
|
+
|
108
99
|
# Build the request
|
109
|
-
#
|
110
100
|
@upload.merge!({
|
111
101
|
bucket_name: (instance_eval &@@callbacks[:bucket_name]), # Allow the application to define a custom bucket name
|
112
102
|
object_key: instance_exec(@upload, &@@callbacks[:object_key]), # The object key should also be generated by the application
|
@@ -114,142 +104,155 @@ module Condo
|
|
114
104
|
})
|
115
105
|
request = residence.new_upload(@upload)
|
116
106
|
resumable = request[:type] == :chunked_upload
|
117
|
-
|
118
|
-
#
|
107
|
+
|
119
108
|
# Save a reference to this upload in the database
|
120
109
|
# => This should throw an error on failure
|
121
|
-
|
122
|
-
|
123
|
-
render :json => request.merge!(:upload_id => upload.id, :residence => residence.name)
|
110
|
+
upload = condo_backend.add_entry(@upload.merge!({provider_name: residence.name, provider_location: residence.location, resumable: resumable}))
|
111
|
+
render json: request.merge!(upload_id: upload.id, residence: residence.name)
|
124
112
|
|
125
113
|
elsif errors.is_a? Hash
|
126
|
-
render :
|
114
|
+
render json: errors, status: :not_acceptable
|
127
115
|
else
|
128
|
-
render :
|
116
|
+
render nothing: true, status: :not_acceptable
|
129
117
|
end
|
130
118
|
end
|
131
119
|
end
|
132
|
-
|
133
|
-
|
134
|
-
#
|
120
|
+
|
135
121
|
# Authorization check all of these
|
136
|
-
#
|
137
122
|
def edit
|
138
|
-
#
|
139
123
|
# Get the signature for parts + final commit
|
140
|
-
#
|
141
124
|
upload = current_upload
|
125
|
+
|
142
126
|
params.require(:part)
|
143
127
|
safe_params = params.permit(:part, :file_id)
|
144
|
-
|
128
|
+
|
145
129
|
if upload.resumable_id.present? && upload.resumable
|
146
|
-
residence =
|
147
|
-
|
130
|
+
residence = current_residence(upload)
|
131
|
+
|
148
132
|
request = residence.set_part({
|
149
|
-
:
|
150
|
-
:
|
151
|
-
:
|
152
|
-
:
|
153
|
-
|
154
|
-
:
|
155
|
-
:
|
133
|
+
bucket_name: upload.bucket_name,
|
134
|
+
object_key: upload.object_key,
|
135
|
+
object_options: upload.object_options,
|
136
|
+
resumable_id: upload.resumable_id,
|
137
|
+
# part may be called 'finish' for commit signature
|
138
|
+
part: safe_params[:part],
|
139
|
+
file_size: upload.file_size,
|
140
|
+
file_id: safe_params[:file_id]
|
156
141
|
})
|
157
|
-
|
158
|
-
render :
|
142
|
+
|
143
|
+
render json: request.merge!(upload_id: upload.id)
|
159
144
|
else
|
160
|
-
render :
|
145
|
+
render nothing: true, status: :not_acceptable
|
161
146
|
end
|
162
147
|
end
|
163
|
-
|
164
|
-
|
148
|
+
|
149
|
+
|
165
150
|
def update
|
166
|
-
#
|
167
151
|
# Provide the upload id after creating a resumable upload (may not be completed)
|
168
152
|
# => We then provide the first part signature
|
169
153
|
#
|
170
154
|
# OR
|
171
155
|
#
|
172
156
|
# Complete an upload
|
173
|
-
|
174
|
-
|
175
|
-
|
157
|
+
upload = current_upload
|
158
|
+
|
159
|
+
safe = params.permit(:resumable_id, {part_list: []}, {part_data: [
|
160
|
+
:md5,
|
161
|
+
:size_bytes,
|
162
|
+
:path,
|
163
|
+
:part
|
164
|
+
]})
|
165
|
+
part_list = safe[:part_list]
|
166
|
+
resumable_id = safe[:resumable_id]
|
167
|
+
|
168
|
+
if resumable_id || part_list
|
176
169
|
if upload.resumable
|
177
|
-
|
178
|
-
|
170
|
+
if part_list
|
171
|
+
upload.part_list = part_list || []
|
172
|
+
|
173
|
+
# We incrementally update this as it might otherwise contain
|
174
|
+
# sum(1 -> 10,000) parts over the time of the upload
|
175
|
+
# (as is the case with the largest file amazon supports)
|
176
|
+
if safe[:part_data]
|
177
|
+
upload.part_data ||= {}
|
178
|
+
safe[:part_data].each do |part|
|
179
|
+
upload.part_data[part[:part]] = part
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
upload.resumable_id = resumable_id if resumable_id
|
185
|
+
upload.save!
|
186
|
+
|
187
|
+
if params[:part_update]
|
188
|
+
render nothing: true
|
189
|
+
else
|
190
|
+
@current_upload = upload
|
191
|
+
|
192
|
+
# Render is called from edit
|
193
|
+
edit
|
194
|
+
end
|
179
195
|
else
|
180
|
-
render :
|
196
|
+
render nothing: true, status: :not_acceptable
|
181
197
|
end
|
182
|
-
|
183
|
-
|
198
|
+
|
199
|
+
else # We are completeing the upload
|
200
|
+
response = instance_exec upload, &@@callbacks[:upload_complete]
|
184
201
|
if response
|
185
|
-
render :
|
202
|
+
render nothing: true
|
186
203
|
else
|
187
|
-
render :
|
204
|
+
render nothing: true, status: :not_acceptable
|
188
205
|
end
|
189
206
|
end
|
190
207
|
end
|
191
|
-
|
192
|
-
|
208
|
+
|
193
209
|
def destroy
|
194
|
-
#
|
195
210
|
# Delete the file from the cloud system - the client is not responsible for this
|
196
|
-
#
|
197
211
|
response = instance_exec current_upload, &@@callbacks[:destroy_upload]
|
198
212
|
if response
|
199
|
-
render :
|
213
|
+
render nothing: true
|
200
214
|
else
|
201
|
-
render :
|
215
|
+
render nothing: true, status: :not_acceptable
|
202
216
|
end
|
203
217
|
end
|
204
|
-
|
205
|
-
|
218
|
+
|
219
|
+
|
206
220
|
protected
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
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]
|
221
|
+
|
222
|
+
|
223
|
+
def current_residence(upload = nil)
|
224
|
+
@current_residence ||= instance_exec(condo_config, current_resident, upload, &@@callbacks[:select_residence])
|
220
225
|
end
|
221
|
-
|
226
|
+
|
222
227
|
def current_upload
|
223
228
|
return @current_upload if @current_upload
|
224
229
|
|
225
230
|
safe_params = params.permit(:upload_id, :id)
|
226
|
-
|
231
|
+
# current_residence.name && current_residence.location && resident.id.exists?
|
232
|
+
@current_upload = condo_backend.check_exists({user_id: current_resident, upload_id: (safe_params[:upload_id] || safe_params[:id])}).tap do |object|
|
227
233
|
raise Condo::Errors::NotYourPlace unless object.present?
|
228
234
|
end
|
229
235
|
end
|
230
|
-
|
236
|
+
|
231
237
|
def current_resident
|
232
|
-
|
238
|
+
# instance_exec for params
|
239
|
+
@current_resident ||= (instance_eval &@@callbacks[:resident_id]).tap do |object|
|
233
240
|
raise Condo::Errors::LostTheKeys unless object.present?
|
234
241
|
end
|
235
242
|
end
|
236
|
-
|
243
|
+
|
237
244
|
def condo_backend
|
238
|
-
Condo::Store
|
245
|
+
::Condo::Store
|
239
246
|
end
|
240
|
-
|
247
|
+
|
241
248
|
def condo_config
|
242
|
-
Condo::Configuration
|
249
|
+
::Condo::Configuration
|
243
250
|
end
|
244
|
-
|
245
|
-
|
246
|
-
#
|
251
|
+
|
252
|
+
|
247
253
|
# Defines the default callbacks
|
248
|
-
#
|
249
254
|
(@@callbacks ||= {}).merge! Condo::Configuration.callbacks
|
250
|
-
|
251
|
-
|
252
|
-
|
255
|
+
|
253
256
|
def self.condo_callback(name, callback = nil, &block)
|
254
257
|
callback ||= block
|
255
258
|
if callback.respond_to?(:call)
|
@@ -258,12 +261,6 @@ module Condo
|
|
258
261
|
raise ArgumentError, 'No callback provided'
|
259
262
|
end
|
260
263
|
end
|
261
|
-
|
262
|
-
|
263
|
-
def self.condo_namespace(name)
|
264
|
-
@@namespace = name.to_sym
|
265
|
-
end
|
266
|
-
|
267
264
|
end
|
268
265
|
end
|
269
266
|
end
|