[ARVADOS] updated: 73d73c7b799ddb60363ddf409d8d301b27c82c00

git at public.curoverse.com git at public.curoverse.com
Wed Apr 30 16:55:36 EDT 2014


Summary of changes:
 .../app/controllers/websocket_controller.rb        |   10 +
 apps/workbench/app/views/websocket/index.html.erb  |   34 ++
 apps/workbench/config/routes.rb                    |    1 +
 services/api/Gemfile                               |    2 +
 services/api/Gemfile.lock                          |    8 +
 .../api/app/controllers/application_controller.rb  |  196 +-------
 .../controllers/arvados/v1/schema_controller.rb    |    6 +
 services/api/app/middlewares/arvados_api_token.rb  |   61 +++
 services/api/app/middlewares/rack_socket.rb        |   86 +++
 services/api/app/models/arvados_model.rb           |   75 ++-
 services/api/app/models/log.rb                     |    4 +-
 services/api/config/application.yml.example        |    7 +
 services/api/config/initializers/authorization.rb  |    5 +
 services/api/config/initializers/eventbus.rb       |   18 +
 .../20140423132913_add_object_owner_to_logs.rb     |   21 +
 services/api/db/schema.rb                          |    1 +
 services/api/lib/eventbus.rb                       |  226 ++++++++
 services/api/lib/load_param.rb                     |   88 +++
 services/api/lib/record_filters.rb                 |   75 +++
 services/api/test/fixtures/logs.yml                |   31 +-
 services/api/test/fixtures/repositories.yml        |    7 +-
 services/api/test/integration/websocket_test.rb    |  570 ++++++++++++++++++++
 services/api/test/test_helper.rb                   |    2 +-
 services/api/test/unit/log_test.rb                 |   21 +
 services/api/test/websocket_runner.rb              |   42 ++
 25 files changed, 1386 insertions(+), 211 deletions(-)
 create mode 100644 apps/workbench/app/controllers/websocket_controller.rb
 create mode 100644 apps/workbench/app/views/websocket/index.html.erb
 create mode 100644 services/api/app/middlewares/arvados_api_token.rb
 create mode 100644 services/api/app/middlewares/rack_socket.rb
 create mode 100644 services/api/config/initializers/authorization.rb
 create mode 100644 services/api/config/initializers/eventbus.rb
 create mode 100644 services/api/db/migrate/20140423132913_add_object_owner_to_logs.rb
 create mode 100644 services/api/lib/eventbus.rb
 create mode 100644 services/api/lib/load_param.rb
 create mode 100644 services/api/lib/record_filters.rb
 create mode 100644 services/api/test/integration/websocket_test.rb
 create mode 100644 services/api/test/websocket_runner.rb

       via  73d73c7b799ddb60363ddf409d8d301b27c82c00 (commit)
       via  02377152d7e368b6b73b2a94ceb68c99f9d55959 (commit)
       via  943feeec776bb75c685cbdee9466f8db3cdf5da7 (commit)
       via  1433693e08e2d4052cc94f6a5902523b08bbc1ac (commit)
       via  e20c9587ad703ae8e1f81251a6e209834a52d448 (commit)
       via  a4724fe92e651abb06acf8c5e75184561a55c854 (commit)
       via  208e172287aba3be7cb988a2c416e4281a2e5f60 (commit)
       via  b0c30631bceb2d1837b52d1d3475e52aee4c9c43 (commit)
       via  b421d5c4754315cdd8b70b6bbea5b5f23fb425de (commit)
       via  e537bd8dd1ac786164f192374e0d076bdc0327f3 (commit)
       via  995dd33ec5bc9ebb7cc4ff075a1f5e1a4e7db20c (commit)
       via  4eb42fd91dc5e50840e0d3db5d5201561602a508 (commit)
       via  7c12fc4d989dd2b4c47a174280a4f9526ecb0798 (commit)
       via  0a72fd5c9f764eba4fc295d8beb24ac3d01885c5 (commit)
       via  87f17f28080eef37ad940a039fd1623e72e3058e (commit)
       via  c72f1de32f688690d1161a1852e471e88919e057 (commit)
       via  f0ca76acaa3a4e3713f7aef6a6bb778e6e71e562 (commit)
       via  1f9df3c7140d4eacf58d4e19a7ddc81260296229 (commit)
       via  aaa65e9d351284278ccb6d3e803fd3dd4f748c31 (commit)
       via  73cf2bb90245787fbbd7c18da51329524c40f6af (commit)
       via  da1614ac6d9b1b2aeba6267b304ce70c1726b608 (commit)
       via  7130989e6493555eba3491cfc9c8dddd1e1a545a (commit)
       via  923e2bd7d962f1a0feefc73ae4f4531c8235a591 (commit)
       via  04cc77648cc62c73433801475c27ede4ceb76c8b (commit)
       via  fa257c28461627fe6700dd8fd2152e380f8725d4 (commit)
       via  cb52a672642bdec7c6a97868a68bbb9b8daa0efb (commit)
       via  d07a96a0f0c11b98ecc927f0b3e0b052f8ef99f7 (commit)
       via  e484a466d78c87114779b596d6ecd79f22088ee2 (commit)
       via  aa920f1659aa830861c196617fe664f35b5c12ef (commit)
       via  c283713dc8762c396407f68129fb276dc4a746fc (commit)
       via  4e047434f0c6958db039cf9ab55e3f7f44da44c9 (commit)
      from  a6439c7ddc3407193889386051f06df2a1e74ea9 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


commit 73d73c7b799ddb60363ddf409d8d301b27c82c00
Merge: 0237715 a6439c7
Author: Peter Amstutz <peter.amstutz at curoverse.com>
Date:   Wed Apr 30 16:55:06 2014 -0400

    Merge branch 'master' of git.clinicalfuture.com:arvados
    
    # Please enter a commit message to explain why this merge is necessary,
    # especially if it merges an updated upstream into a topic branch.
    #
    # Lines starting with '#' will be ignored, and an empty message aborts
    # the commit.


commit 02377152d7e368b6b73b2a94ceb68c99f9d55959
Merge: e8f8180 943feee
Author: Peter Amstutz <peter.amstutz at curoverse.com>
Date:   Wed Apr 30 16:54:40 2014 -0400

    Merge branch 'origin-2608-websocket-event-bus-alt2'
    
    Conflicts:
    	services/api/app/models/arvados_model.rb
    	services/api/test/test_helper.rb

diff --cc services/api/app/controllers/application_controller.rb
index f83cd34,3891bde..4b5a27d
--- a/services/api/app/controllers/application_controller.rb
+++ b/services/api/app/controllers/application_controller.rb
@@@ -1,21 -4,20 +4,22 @@@ require 'record_filters
  class ApplicationController < ActionController::Base
    include CurrentApiClient
    include ThemesForRails::ActionController
+   include LoadParam
+   include RecordFilters
  
 +  ERROR_ACTIONS = [:render_error, :render_not_found]
 +
    respond_to :json
    protect_from_forgery
  
-   around_filter :thread_with_auth_info, except: ERROR_ACTIONS
    before_filter :respond_with_json_by_default
    before_filter :remote_ip
 -  before_filter :require_auth_scope, :except => :render_not_found
 -  before_filter :catch_redirect_hint
 +  before_filter :load_read_auths
 +  before_filter :require_auth_scope, except: ERROR_ACTIONS
  
 -  before_filter :find_object_by_uuid, :except => [:index, :create,
 -                                                  :render_error,
 -                                                  :render_not_found]
 +  before_filter :catch_redirect_hint
 +  before_filter(:find_object_by_uuid,
 +                except: [:index, :create] + ERROR_ACTIONS)
    before_filter :load_limit_offset_order_params, only: [:index, :owned_items]
    before_filter :load_where_param, only: [:index, :owned_items]
    before_filter :load_filters_param, only: [:index, :owned_items]
@@@ -178,79 -179,8 +180,8 @@@
  
    protected
  
-   def load_where_param
-     if params[:where].nil? or params[:where] == ""
-       @where = {}
-     elsif params[:where].is_a? Hash
-       @where = params[:where]
-     elsif params[:where].is_a? String
-       begin
-         @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
-     @filters ||= []
-     if params[:filters].is_a? Array
-       @filters += params[:filters]
-     elsif params[:filters].is_a? String and !params[:filters].empty?
-       begin
-         f = Oj.load params[:filters]
-         raise unless f.is_a? Array
-         @filters += f
-       rescue
-         raise ArgumentError.new("Could not parse \"filters\" param as an array")
-       end
-     end
-   end
- 
-   def default_orders
-     ["#{table_name}.modified_at desc"]
-   end
- 
-   def load_limit_offset_order_params
-     if params[:limit]
-       unless params[:limit].to_s.match(/^\d+$/)
-         raise ArgumentError.new("Invalid value for limit parameter")
-       end
-       @limit = params[:limit].to_i
-     else
-       @limit = DEFAULT_LIMIT
-     end
- 
-     if params[:offset]
-       unless params[:offset].to_s.match(/^\d+$/)
-         raise ArgumentError.new("Invalid value for offset parameter")
-       end
-       @offset = params[:offset].to_i
-     else
-       @offset = 0
-     end
- 
-     @orders = []
-     if params[:order]
-       params[:order].split(',').each do |order|
-         attr, direction = order.strip.split " "
-         direction ||= 'asc'
-         if attr.match /^[a-z][_a-z0-9]+$/ and
-             model_class.columns.collect(&:name).index(attr) and
-             ['asc','desc'].index direction.downcase
-           @orders << "#{table_name}.#{attr} #{direction.downcase}"
-         end
-       end
-     end
-     if @orders.empty?
-       @orders = default_orders
-     end
-   end
- 
    def find_objects_for_index
 -    @objects ||= model_class.readable_by(current_user)
 +    @objects ||= model_class.readable_by(*@read_users)
      apply_where_limit_order_params
    end
  
diff --cc services/api/app/models/arvados_model.rb
index f7da9df,097b8db..1dcd9e2
--- a/services/api/app/models/arvados_model.rb
+++ b/services/api/app/models/arvados_model.rb
@@@ -59,39 -59,65 +59,71 @@@ class ArvadosModel < ActiveRecord::Bas
      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$/
--  #     if (re and
--  #         self.respond_to? re[1].to_sym and
--  #         (auuid = self.send((re[1] + '_uuid').to_sym)) and
--  #         (aclass = self.class.kind_class(self.send(col.name.to_sym))) and
--  #         (aobject = aclass.where('uuid=?', auuid).first))
--  #       self.instance_variable_set('@'+re[1], aobject)
--  #     end
--  #   end
--  # end
--
 -  def self.readable_by user
 -    if user.is_admin
 -      # Admins can read anything, so return immediately.
 -      return self
 -    end
++  # Return a query with read permissions restricted to the union of of the
++  # permissions of the members of users_list, i.e. if something is readable by
++  # any user in users_list, it will be readable in the query returned by this
++  # function.
 +  def self.readable_by(*users_list)
++    # Get rid of troublesome nils
 +    users_list.compact!
-     user_uuids = users_list.map { |u| u.uuid }
-     uuid_list = user_uuids + users_list.flat_map { |u| u.groups_i_can(:read) }
-     sanitized_uuid_list = uuid_list.
-       collect { |uuid| sanitize(uuid) }.join(', ')
-     sql_conds = []
-     sql_params = []
++
++    # Check if any of the users are admin.  If so, we're done.
 +    if users_list.select { |u| u.is_admin }.empty?
++
++      # Collect the uuids for each user and any groups readable by each user.
++      user_uuids = users_list.map { |u| u.uuid }
++      uuid_list = user_uuids + users_list.flat_map { |u| u.groups_i_can(:read) }
++      sanitized_uuid_list = uuid_list.
++        collect { |uuid| sanitize(uuid) }.join(', ')
++      sql_conds = []
++      sql_params = []
++      or_object_uuid = ''
++
++      # This row is owned by a member of users_list, or owned by a group
++      # readable by a member of users_list
++      # or
++      # This row uuid is the uuid of a member of users_list
++      # or
++      # A permission link exists ('write' and 'manage' implicitly include
++      # 'read') from a member of users_list, or a group readable by users_list,
++      # to this row, or to the owner of this row (see join() below).
 +      sql_conds += ["#{table_name}.owner_uuid in (?)",
 +                    "#{table_name}.uuid in (?)",
 +                    "permissions.head_uuid IS NOT NULL"]
 +      sql_params += [uuid_list, user_uuids]
++
 +      if self == Link and users_list.any?
++        # This row is a 'permission' or 'resources' link class
++        # The uuid for a member of users_list is referenced in either the head
++        # or tail of the link
 +        sql_conds += ["(#{table_name}.link_class in (#{sanitize 'permission'}, #{sanitize 'resources'}) AND (#{table_name}.head_uuid IN (?) OR #{table_name}.tail_uuid IN (?)))"]
 +        sql_params += [user_uuids, user_uuids]
 +      end
+ 
 -    uuid_list = [user.uuid, *user.groups_i_can(:read)]
 -    sanitized_uuid_list = uuid_list.
 -      collect { |uuid| sanitize(uuid) }.join(', ')
 -    or_references_me = ''
++      if self == Log and users_list.any?
++        # Link head points to the object described by this row
++        or_object_uuid = ", #{table_name}.object_uuid"
+ 
 -    if self == User
 -      or_row_is_me = "OR (#{table_name}.uuid=#{sanitize user.uuid})"
 -    end
++        # This object described by this row is owned by this user, or owned by a group readable by this user
++        sql_conds += ["#{table_name}.object_owner_uuid in (?)"]
++        sql_params += [uuid_list]
++      end
+ 
 -    if self == Link
 -      or_references_me = "OR (#{table_name}.link_class in (#{sanitize 'permission'}, #{sanitize 'resources'}) AND #{sanitize user.uuid} IN (#{table_name}.head_uuid, #{table_name}.tail_uuid))"
 -    end
++      # Link head points to this row, or to the owner of this row (the thing to be read)
++      #
++      # Link tail originates from this user, or a group that is readable by this
++      # user (the identity with authorization to read)
++      #
++      # Link class is 'permission' ('write' and 'manage' implicitly include 'read')
++
++      joins("LEFT JOIN links permissions ON permissions.head_uuid in (#{table_name}.owner_uuid, #{table_name}.uuid #{or_object_uuid}) AND permissions.tail_uuid in (#{sanitized_uuid_list}) AND permissions.link_class='permission'")
++        .where(sql_conds.join(' OR '), *sql_params).uniq
+ 
 -    if self == Log
 -      or_object_uuid = ", #{table_name}.object_uuid"
 -      or_object_owner = "OR (#{table_name}.object_owner_uuid in (#{sanitized_uuid_list}))"
++    else
++      # At least one user is admin, so don't bother to apply any restrictions.
++      self
      end
-     joins("LEFT JOIN links permissions ON permissions.head_uuid in (#{table_name}.owner_uuid, #{table_name}.uuid) AND permissions.tail_uuid in (#{sanitized_uuid_list}) AND permissions.link_class='permission'")
-       .where(sql_conds.join(' OR '), *sql_params)
+ 
 -    # Link head points to this row, or to the owner of this row (the thing to be read)
 -    # (or the object described by this row, for logs table only)
 -    # Link tail originates from this user, or a group that is readable by this
 -    # user (the identity with authorization to read)
 -    # Link is any permission link ('write' and 'manage' implicitly include 'read')
 -    # The existence of such a link is tested in the where clause as permissions.head_uuid IS NOT NULL.
 -    # or
 -    # This row is owned by this user, or owned by a group readable by this user
 -    # or
 -    # This is the users table
 -    # This row uuid is equal this user uuid
 -    # or
 -    # This is the links table
 -    # This row is a permission link
 -    # The current user is referenced in either the head or tail of the link
 -    # or
 -    # This is the logs table
 -    # This object described by this row is owned by this user, or owned by a group readable by this user
 -
 -    joins("LEFT JOIN links permissions ON permissions.head_uuid in (#{table_name}.owner_uuid, #{table_name}.uuid #{or_object_uuid}) AND permissions.tail_uuid in (#{sanitized_uuid_list}) AND permissions.link_class='permission'").
 -      where("permissions.head_uuid IS NOT NULL OR #{table_name}.owner_uuid in (?) #{or_row_is_me} #{or_references_me} #{or_object_owner}",
 -            uuid_list).uniq
    end
  
    def logged_attributes
diff --cc services/api/test/test_helper.rb
index 3e81ff7,70988ad..869d87f
--- a/services/api/test/test_helper.rb
+++ b/services/api/test/test_helper.rb
@@@ -37,9 -21,15 +37,9 @@@ class ActiveSupport::TestCas
      self.request.headers["Accept"] = "text/json"
    end
  
 -  def json_response
 -    @json_response ||= ActiveSupport::JSON.decode @response.body
 -  end
 -
    def authorize_with(api_client_auth_name)
-     self.request.env['HTTP_AUTHORIZATION'] = "OAuth2 #{api_token(api_client_auth_name)}"
+     ArvadosApiToken.new.call ({"rack.input" => "", "HTTP_AUTHORIZATION" => "OAuth2 #{api_client_authorizations(api_client_auth_name).api_token}"})
    end
 -
 -  # Add more helper methods to be used by all tests here...
  end
  
  class ActionDispatch::IntegrationTest

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list