lib/condo.rb in condo-1.0.6 vs lib/condo.rb in condo-2.0.0

- old
+ new

@@ -1,54 +1,50 @@ +# encoding: utf-8 + +require 'fog' require 'condo/engine' require 'condo/errors' require 'condo/configuration' module Condo def self.included(base) base.class_eval do - - + + def new - # # Returns the provider that will be used for this file upload resident = current_resident - # # Ensure parameters are correct params.require(:file_size) params.require(:file_name) permitted = params.permit(:file_size, :file_name, :file_path) @upload = { file_size: permitted[:file_size].to_i, file_name: @@callbacks[:sanitize_filename].call(permitted[:file_name]) } @upload[:file_path] = @@callbacks[:sanitize_filepath].call(permitted[:file_path]) if permitted[:file_path] - + valid, errors = instance_exec(@upload, &@@callbacks[:pre_validation]) # Ensure the upload request is valid before uploading - if !!valid - set_residence(nil, {:resident => resident, :params => @upload}) if condo_config.dynamic_provider_present?(@@namespace) + if valid residence = current_residence - - render :json => {:residence => residence.name} - + + render json: {residence: residence.name} elsif errors.is_a? Hash - render :json => errors, :status => :not_acceptable + render json: errors, status: :not_acceptable else - render :nothing => true, :status => :not_acceptable + render nothing: true, status: :not_acceptable end end - + def create - # # Check for existing upload or create a new one # => mutually exclusive so can send back either the parts signature from show or a bucket creation signature and the upload_id - # resident = current_resident - - # + # Ensure parameters are correct params.require(:file_size) params.require(:file_name) params.require(:file_id) permitted = params.permit(:file_size, :file_name, :file_path, :file_id) @@ -57,213 +53,214 @@ file_name: @@callbacks[:sanitize_filename].call(permitted[:file_name]), file_id: permitted[:file_id], user_id: resident } @upload[:file_path] = @@callbacks[:sanitize_filepath].call(permitted[:file_path]) if permitted[:file_path] - - # + # Check for existing uploads upload = condo_backend.check_exists(@upload) - + if upload.present? - residence = set_residence(upload.provider_name, { - :location => upload.provider_location, - :upload => upload - }) - - # + residence = current_residence(upload) + # Return the parts or direct upload sig - # request = nil if upload.resumable_id.present? && upload.resumable request = residence.get_parts({ - :bucket_name => upload.bucket_name, - :object_key => upload.object_key, - :object_options => upload.object_options, - :file_size => upload.file_size, - :resumable_id => upload.resumable_id + bucket_name: upload.bucket_name, + object_key: upload.object_key, + object_options: upload.object_options, + file_size: upload.file_size, + resumable_id: upload.resumable_id }) + + request[:part_list] = upload.part_list || [] + request[:part_data] = upload.part_data if upload.part_data else request = residence.new_upload({ - :bucket_name => upload.bucket_name, - :object_key => upload.object_key, - :object_options => upload.object_options, - :file_size => upload.file_size, - :file_id => upload.file_id + bucket_name: upload.bucket_name, + object_key: upload.object_key, + object_options: upload.object_options, + file_size: upload.file_size, + file_id: upload.file_id }) end - render :json => request.merge(:upload_id => upload.id, :residence => residence.name) + render json: request.merge!({ + upload_id: upload.id, + residence: residence.name + }) else - # # Create a new upload - # valid, errors = instance_exec(@upload, &@@callbacks[:pre_validation]) # Ensure the upload request is valid before uploading - - + if valid - set_residence(nil, {:resident => resident, :params => @upload}) if condo_config.dynamic_provider_present?(@@namespace) residence = current_residence - - # + # Build the request - # @upload.merge!({ bucket_name: (instance_eval &@@callbacks[:bucket_name]), # Allow the application to define a custom bucket name object_key: instance_exec(@upload, &@@callbacks[:object_key]), # The object key should also be generated by the application object_options: instance_exec(@upload, &@@callbacks[:object_options]) # Do we want to mess with any of the options? }) request = residence.new_upload(@upload) resumable = request[:type] == :chunked_upload - - # + # Save a reference to this upload in the database # => This should throw an error on failure - # - upload = condo_backend.add_entry(@upload.merge!({:provider_name => residence.name, :provider_location => residence.location, :resumable => resumable})) - render :json => request.merge!(:upload_id => upload.id, :residence => residence.name) + upload = condo_backend.add_entry(@upload.merge!({provider_name: residence.name, provider_location: residence.location, resumable: resumable})) + render json: request.merge!(upload_id: upload.id, residence: residence.name) elsif errors.is_a? Hash - render :json => errors, :status => :not_acceptable + render json: errors, status: :not_acceptable else - render :nothing => true, :status => :not_acceptable + render nothing: true, status: :not_acceptable end end end - - - # + # Authorization check all of these - # def edit - # # Get the signature for parts + final commit - # upload = current_upload + params.require(:part) safe_params = params.permit(:part, :file_id) - + if upload.resumable_id.present? && upload.resumable - residence = set_residence(upload.provider_name, {:location => upload.provider_location, :upload => upload}) - + residence = current_residence(upload) + request = residence.set_part({ - :bucket_name => upload.bucket_name, - :object_key => upload.object_key, - :object_options => upload.object_options, - :resumable_id => upload.resumable_id, - :part => safe_params[:part], # part may be called 'finish' for commit signature - :file_size => upload.file_size, - :file_id => safe_params[:file_id] + bucket_name: upload.bucket_name, + object_key: upload.object_key, + object_options: upload.object_options, + resumable_id: upload.resumable_id, + # part may be called 'finish' for commit signature + part: safe_params[:part], + file_size: upload.file_size, + file_id: safe_params[:file_id] }) - - render :json => request.merge!(:upload_id => upload.id) + + render json: request.merge!(upload_id: upload.id) else - render :nothing => true, :status => :not_acceptable + render nothing: true, status: :not_acceptable end end - - + + def update - # # Provide the upload id after creating a resumable upload (may not be completed) # => We then provide the first part signature # # OR # # Complete an upload - # - if params[:resumable_id] - upload = current_upload + upload = current_upload + + safe = params.permit(:resumable_id, {part_list: []}, {part_data: [ + :md5, + :size_bytes, + :path, + :part + ]}) + part_list = safe[:part_list] + resumable_id = safe[:resumable_id] + + if resumable_id || part_list if upload.resumable - @current_upload = upload.update_entry :resumable_id => params.permit(:resumable_id)[:resumable_id] - edit + if part_list + upload.part_list = part_list || [] + + # We incrementally update this as it might otherwise contain + # sum(1 -> 10,000) parts over the time of the upload + # (as is the case with the largest file amazon supports) + if safe[:part_data] + upload.part_data ||= {} + safe[:part_data].each do |part| + upload.part_data[part[:part]] = part + end + end + end + + upload.resumable_id = resumable_id if resumable_id + upload.save! + + if params[:part_update] + render nothing: true + else + @current_upload = upload + + # Render is called from edit + edit + end else - render :nothing => true, :status => :not_acceptable + render nothing: true, status: :not_acceptable end - else - response = instance_exec current_upload, &@@callbacks[:upload_complete] + + else # We are completeing the upload + response = instance_exec upload, &@@callbacks[:upload_complete] if response - render :nothing => true + render nothing: true else - render :nothing => true, :status => :not_acceptable + render nothing: true, status: :not_acceptable end end end - - + def destroy - # # Delete the file from the cloud system - the client is not responsible for this - # response = instance_exec current_upload, &@@callbacks[:destroy_upload] if response - render :nothing => true + render nothing: true else - render :nothing => true, :status => :not_acceptable + render nothing: true, status: :not_acceptable end end - - + + protected - - - # - # A before filter can be used to select the cloud provider for the current user - # Otherwise the dynamic residence can be used when users are define their own storage locations - # - def set_residence(name, options = {}) - options[:namespace] = @@namespace - @current_residence = condo_config.set_residence(name, options) + + + def current_residence(upload = nil) + @current_residence ||= instance_exec(condo_config, current_resident, upload, &@@callbacks[:select_residence]) end - - def current_residence - @current_residence ||= condo_config.residencies[0] - end - + def current_upload return @current_upload if @current_upload safe_params = params.permit(:upload_id, :id) - @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? + # current_residence.name && current_residence.location && resident.id.exists? + @current_upload = condo_backend.check_exists({user_id: current_resident, upload_id: (safe_params[:upload_id] || safe_params[:id])}).tap do |object| raise Condo::Errors::NotYourPlace unless object.present? end end - + def current_resident - @current_resident ||= (instance_eval &@@callbacks[:resident_id]).tap do |object| # instance_exec for params + # instance_exec for params + @current_resident ||= (instance_eval &@@callbacks[:resident_id]).tap do |object| raise Condo::Errors::LostTheKeys unless object.present? end end - + def condo_backend - Condo::Store + ::Condo::Store end - + def condo_config - Condo::Configuration.instance + ::Condo::Configuration end - - - # + + # Defines the default callbacks - # (@@callbacks ||= {}).merge! Condo::Configuration.callbacks - @@namespace ||= :global - - + def self.condo_callback(name, callback = nil, &block) callback ||= block if callback.respond_to?(:call) @@callbacks[name.to_sym] = callback else raise ArgumentError, 'No callback provided' end end - - - def self.condo_namespace(name) - @@namespace = name.to_sym - end - end end end