Merge branch 'master' into 2257-inequality-conditions
authorTom Clegg <tom@curoverse.com>
Fri, 14 Mar 2014 14:17:46 +0000 (10:17 -0400)
committerTom Clegg <tom@curoverse.com>
Fri, 14 Mar 2014 14:17:46 +0000 (10:17 -0400)
1  2 
services/api/app/controllers/application_controller.rb
services/api/app/models/arvados_model.rb

index 8ed554f8ca9d0798bf0b011a226d71848463e6d4,7c10c8425ddc51114ce81f791702c504bd48d524..2d37dc18cdeb8732e3cc78181048102c43d9ffbf
@@@ -10,7 -10,6 +10,7 @@@ class ApplicationController < ActionCon
    before_filter :catch_redirect_hint
  
    before_filter :load_where_param, :only => :index
 +  before_filter :load_filters_param, :only => :index
    before_filter :find_objects_for_index, :only => :index
    before_filter :find_object_by_uuid, :except => [:index, :create,
                                                    :render_error,
@@@ -39,7 -38,7 +39,7 @@@
      if @object.save
        show
      else
-       render_error "Save failed"
+       raise "Save failed"
      end
    end
  
@@@ -50,7 -49,7 +50,7 @@@
      if @object.update_attributes attrs_to_update
        show
      else
-       render_error "Update failed"
+       raise "Update failed"
      end
    end
  
@@@ -88,7 -87,9 +88,9 @@@
  
    def render_error(e)
      logger.error e.inspect
-     logger.error e.backtrace.collect { |x| x + "\n" }.join('') if e.backtrace
+     if e.respond_to? :backtrace and e.backtrace
+       logger.error e.backtrace.collect { |x| x + "\n" }.join('')
+     end
      if @object and @object.errors and @object.errors.full_messages and not @object.errors.full_messages.empty?
        errors = @object.errors.full_messages
      else
        @where = params[:where]
      elsif params[:where].is_a? String
        begin
 -        @where = Oj.load(params[:where], symbol_keys: true)
 +        @where = Oj.load(params[:where])
 +        raise unless @where.is_a? Hash
        rescue
          raise ArgumentError.new("Could not parse \"where\" param as an object")
        end
      end
 +    @where = @where.with_indifferent_access
 +  end
 +
 +  def load_filters_param
 +    if params[:filters].is_a? Array
 +      @filters = params[:filters]
 +    elsif params[:filters].is_a? String
 +      begin
 +        @filters = Oj.load params[:filters]
 +        raise unless @filters.is_a? Array
 +      rescue
 +        raise ArgumentError.new("Could not parse \"filters\" param as an array")
 +      end
 +    end
    end
  
    def find_objects_for_index
      @objects ||= model_class.readable_by(current_user)
 -    if !@where.empty?
 +    apply_where_limit_order_params
 +  end
 +
 +  def apply_where_limit_order_params
 +    if @filters.is_a? Array and @filters.any?
 +      cond_out = []
 +      param_out = []
 +      @filters.each do |attr, operator, operand|
 +        if !model_class.searchable_columns.index attr.to_s
 +          raise ArgumentError.new("Invalid attribute '#{attr}' in condition")
 +        end
 +        case operator.downcase
 +        when '=', '<', '<=', '>', '>=', 'like'
 +          if operand.is_a? String
 +            cond_out << "#{table_name}.#{attr} #{operator} ?"
 +            if operator.match(/[<=>]/) and
 +                model_class.attribute_column(attr).type == :datetime
 +              operand = Time.parse operand
 +            end
 +            param_out << operand
 +          end
 +        when 'in'
 +          if operand.is_a? Array
 +            cond_out << "#{table_name}.#{attr} IN (?)"
 +            param_out << operand
 +          end
 +        end
 +      end
 +      if cond_out.any?
 +        @objects = @objects.where(cond_out.join(' AND '), *param_out)
 +      end
 +    end
 +    if @where.is_a? Hash and @where.any?
        conditions = ['1=1']
        @where.each do |attr,value|
          if attr == :any
        if supplied_token
          api_client_auth = ApiClientAuthorization.
            includes(:api_client, :user).
-           where('api_token=? and (expires_at is null or expires_at > now())', supplied_token).
+           where('api_token=? and (expires_at is null or expires_at > CURRENT_TIMESTAMP)', supplied_token).
            first
          if api_client_auth.andand.user
            session[:user_id] = api_client_auth.user.id
  
    def self._index_requires_parameters
      {
 +      filters: { type: 'array', required: false },
        where: { type: 'object', required: false },
        order: { type: 'string', required: false }
      }
    end
  
    def render *opts
-     response = opts.first[:json]
-     if response.is_a?(Hash) &&
-         params[:_profile] &&
-         Thread.current[:request_starttime]
-       response[:_profile] = {
-          request_time: Time.now - Thread.current[:request_starttime]
-       }
+     if opts.first
+       response = opts.first[:json]
+       if response.is_a?(Hash) &&
+           params[:_profile] &&
+           Thread.current[:request_starttime]
+         response[:_profile] = {
+           request_time: Time.now - Thread.current[:request_starttime]
+         }
+       end
      end
      super *opts
    end
index 9475f0dd1d5d819b832ba460986f348887cc38c8,c89efdf404abb3a0f7f9a374562851b57abe372d..84bdf957632d2c35999d1d247a2abcf342fd207d
@@@ -40,16 -40,12 +40,16 @@@ class ArvadosModel < ActiveRecord::Bas
  
    def self.searchable_columns
      self.columns.collect do |col|
 -      if [:string, :text].index(col.type) && col.name != 'owner_uuid'
 +      if [:string, :text, :datetime].index(col.type) && col.name != 'owner_uuid'
          col.name
        end
      end.compact
    end
  
 +  def self.attribute_column attr
 +    self.columns.select { |col| col.name == attr.to_s }.first
 +  end
 +
    def eager_load_associations
      self.class.columns.each do |col|
        re = col.name.match /^(.*)_kind$/
  
    def update_modified_by_fields
      self.created_at ||= Time.now
-     self.owner_uuid ||= current_default_owner
+     self.owner_uuid ||= current_default_owner if self.respond_to? :owner_uuid=
      self.modified_at = Time.now
      self.modified_by_user_uuid = current_user ? current_user.uuid : nil
      self.modified_by_client_uuid = current_api_client ? current_api_client.uuid : nil