Merge branch '2257-inequality-conditions' into 2290-user-activity
[arvados.git] / apps / workbench / app / models / arvados_base.rb
index 2aa91f735eb67e3299b09c055531d231e569f82c..4ba53b952992d043e8ee04fce98db7f307f84286 100644 (file)
@@ -3,21 +3,22 @@ class ArvadosBase < ActiveRecord::Base
   attr_accessor :attribute_sortkey
 
   def self.uuid_infix_object_kind
-    @@uuid_infix_object_kind ||= {
-      '4zz18' => 'arvados#collection',
-      'tpzed' => 'arvados#user',
-      'ozdt8' => 'arvados#api_client',
-      '8i9sb' => 'arvados#job',
-      'o0j2j' => 'arvados#link',
-      '57u5n' => 'arvados#log',
-      'j58dm' => 'arvados#specimen',
-      'p5p6p' => 'arvados#pipeline_template',
-      'mxsvm' => 'arvados#pipeline_template', # legacy Pipeline objects
-      'd1hrv' => 'arvados#pipeline_instance',
-      'uo14g' => 'arvados#pipeline_instance', # legacy PipelineInstance objects
-      'j7d0g' => 'arvados#group',
-      'ldvyl' => 'arvados#group' # only needed for legacy Project objects
-    }
+    @@uuid_infix_object_kind ||=
+      begin
+        infix_kind = {}
+        $arvados_api_client.discovery[:schemas].each do |name, schema|
+          if schema[:uuidPrefix]
+            infix_kind[schema[:uuidPrefix]] =
+              'arvados#' + name.to_s.camelcase(:lower)
+          end
+        end
+
+        # Recognize obsolete types.
+        infix_kind.
+          merge('mxsvm' => 'arvados#pipelineTemplate', # Pipeline
+                'uo14g' => 'arvados#pipelineInstance', # PipelineInvocation
+                'ldvyl' => 'arvados#group') # Project
+      end
   end
 
   def initialize(*args)
@@ -25,11 +26,11 @@ class ArvadosBase < ActiveRecord::Base
     @attribute_sortkey ||= {
       'id' => nil,
       'uuid' => '000',
-      'owner' => '001',
+      'owner_uuid' => '001',
       'created_at' => '002',
       'modified_at' => '003',
-      'modified_by_user' => '004',
-      'modified_by_client' => '005',
+      'modified_by_user_uuid' => '004',
+      'modified_by_client_uuid' => '005',
       'name' => '050',
       'tail_kind' => '100',
       'tail_uuid' => '100',
@@ -60,34 +61,57 @@ class ArvadosBase < ActiveRecord::Base
     attr_reader :kind
     @columns
   end
+
   def self.column(name, sql_type = nil, default = nil, null = true)
     ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null)
   end
+
   def self.attribute_info
     self.columns
     @attribute_info
   end
-  def self.find(uuid)
+
+  def self.find(uuid, opts={})
     if uuid.class != String or uuid.length < 27 then
       raise 'argument to find() must be a uuid string. Acceptable formats: warehouse locator or string with format xxxxx-xxxxx-xxxxxxxxxxxxxxx'
     end
-    new.private_reload(uuid)
+
+    # Only do one lookup on the API side per {class, uuid, workbench
+    # request} unless {cache: false} is given via opts.
+    cache_key = "request_#{Thread.current.object_id}_#{self.to_s}_#{uuid}"
+    if opts[:cache] == false
+      Rails.cache.write cache_key, $arvados_api_client.api(self, '/' + uuid)
+    end
+    hash = Rails.cache.fetch cache_key do
+      $arvados_api_client.api(self, '/' + uuid)
+    end
+    new.private_reload(hash)
   end
+
   def self.order(*args)
     ArvadosResourceList.new(self).order(*args)
   end
+
+  def self.filter(*args)
+    ArvadosResourceList.new(self).filter(*args)
+  end
+
   def self.where(*args)
     ArvadosResourceList.new(self).where(*args)
   end
+
   def self.limit(*args)
     ArvadosResourceList.new(self).limit(*args)
   end
+
   def self.eager(*args)
     ArvadosResourceList.new(self).eager(*args)
   end
+
   def self.all(*args)
     ArvadosResourceList.new(self).all(*args)
   end
+
   def save
     obdata = {}
     self.class.columns.each do |col|
@@ -109,14 +133,19 @@ class ArvadosBase < ActiveRecord::Base
     @kind = resp[:kind]
 
     # these attrs can be modified by "save" -- we should update our copies
-    %w(uuid owner created_at
-       modified_at modified_by_user modified_by_client
+    %w(uuid owner_uuid created_at
+       modified_at modified_by_user_uuid modified_by_client_uuid
       ).each do |attr|
-      self.send(attr + '=', resp[attr.to_sym])
+      if self.respond_to? "#{attr}=".to_sym
+        self.send(attr + '=', resp[attr.to_sym])
+      end
     end
 
+    @new_record = false
+
     self
   end
+
   def save!
     self.save or raise Exception.new("Save failed")
   end
@@ -156,6 +185,7 @@ class ArvadosBase < ActiveRecord::Base
     @links = $arvados_api_client.api Link, '', { _method: 'GET', where: o, eager: true }
     @links = $arvados_api_client.unpack_api_response(@links)
   end
+
   def all_links
     return @all_links if @all_links
     res = $arvados_api_client.api Link, '', {
@@ -168,9 +198,11 @@ class ArvadosBase < ActiveRecord::Base
     }
     @all_links = $arvados_api_client.unpack_api_response(res)
   end
+
   def reload
     private_reload(self.uuid)
   end
+
   def private_reload(uuid_or_hash)
     raise "No such object" if !uuid_or_hash
     if uuid_or_hash.is_a? Hash
@@ -193,8 +225,14 @@ class ArvadosBase < ActiveRecord::Base
       end
     end
     @all_links = nil
+    @new_record = false
     self
   end
+
+  def to_param
+    uuid
+  end
+
   def dup
     super.forget_uuid!
   end
@@ -212,18 +250,20 @@ class ArvadosBase < ActiveRecord::Base
   end
 
   def editable?
-    (current_user and
+    (current_user and current_user.is_active and
      (current_user.is_admin or
-      current_user.uuid == self.owner))
+      current_user.uuid == self.owner_uuid))
   end
 
   def attribute_editable?(attr)
-    if "created_at modified_at modified_by_user modified_by_client updated_at".index(attr.to_s)
+    if "created_at modified_at modified_by_user_uuid modified_by_client_uuid updated_at".index(attr.to_s)
+      false
+    elsif not (current_user.andand.is_active)
       false
-    elsif "uuid owner".index(attr.to_s)
-      current_user and current_user.is_admin
+    elsif "uuid owner_uuid".index(attr.to_s) or current_user.is_admin
+      current_user.is_admin
     else
-      current_user and current_user.uuid == owner
+      current_user.uuid == self.owner_uuid or current_user.uuid == self.uuid
     end
   end
 
@@ -256,6 +296,14 @@ class ArvadosBase < ActiveRecord::Base
     resource_class
   end
 
+  def friendly_link_name
+    (name if self.respond_to? :name) || uuid
+  end
+
+  def selection_label
+    friendly_link_name
+  end
+
   protected
 
   def forget_uuid!