X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/5225a4deab9bf526d4e178cb5220f790b3d33e67..ef47dfeb871015d9da6d5e2e0a04100c2e9e8eee:/apps/workbench/app/models/arvados_base.rb diff --git a/apps/workbench/app/models/arvados_base.rb b/apps/workbench/app/models/arvados_base.rb index a648a8f07d..1a0da6424a 100644 --- a/apps/workbench/app/models/arvados_base.rb +++ b/apps/workbench/app/models/arvados_base.rb @@ -3,40 +3,45 @@ 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) super(*args) @attribute_sortkey ||= { 'id' => nil, - 'uuid' => '000', - 'owner_uuid' => '001', - 'created_at' => '002', - 'modified_at' => '003', - 'modified_by_user_uuid' => '004', - 'modified_by_client_uuid' => '005', - 'name' => '050', - 'tail_kind' => '100', - 'tail_uuid' => '100', - 'head_kind' => '101', - 'head_uuid' => '101', - 'info' => 'zzz-000', - 'updated_at' => 'zzz-999' + 'name' => '000', + 'owner_uuid' => '002', + 'event_type' => '100', + 'link_class' => '100', + 'group_class' => '100', + 'tail_uuid' => '101', + 'head_uuid' => '102', + 'object_uuid' => '102', + 'summary' => '104', + 'description' => '104', + 'properties' => '150', + 'info' => '150', + 'created_at' => '200', + 'modified_at' => '201', + 'modified_by_user_uuid' => '202', + 'modified_by_client_uuid' => '203', + 'uuid' => '999', } end @@ -44,50 +49,83 @@ class ArvadosBase < ActiveRecord::Base return @columns unless @columns.nil? @columns = [] @attribute_info ||= {} - return @columns if $arvados_api_client.arvados_schema[self.to_s.to_sym].nil? - $arvados_api_client.arvados_schema[self.to_s.to_sym].each do |coldef| - k = coldef[:name].to_sym - if coldef[:type] == coldef[:type].downcase - @columns << column(k, coldef[:type].to_sym) + schema = $arvados_api_client.discovery[:schemas][self.to_s.to_sym] + return @columns if schema.nil? + schema[:properties].each do |k, coldef| + case k + when :etag, :kind + attr_reader k else - @columns << column(k, :text) - serialize k, coldef[:type].constantize + if coldef[:type] == coldef[:type].downcase + # boolean, integer, etc. + @columns << column(k, coldef[:type].to_sym) + else + # Hash, Array + @columns << column(k, :text) + serialize k, coldef[:type].constantize + end + attr_accessible k + @attribute_info[k] = coldef end - attr_accessible k - @attribute_info[k] = coldef end - attr_reader :etag - 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) + + if self == ArvadosBase + # Determine type from uuid and defer to the appropriate subclass. + return resource_class_for_uuid(uuid).find(uuid, opts) + end + + # 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| @@ -108,17 +146,18 @@ class ArvadosBase < ActiveRecord::Base @etag = resp[:etag] @kind = resp[:kind] - # these attrs can be modified by "save" -- we should update our copies - %w(uuid owner_uuid created_at - modified_at modified_by_user_uuid modified_by_client_uuid - ).each do |attr| + # attributes can be modified during "save" -- we should update our copies + resp.keys.each do |attr| if self.respond_to? "#{attr}=".to_sym - self.send(attr + '=', resp[attr.to_sym]) + self.send(attr.to_s + '=', resp[attr.to_sym]) end end + @new_record = false + self end + def save! self.save or raise Exception.new("Save failed") end @@ -132,14 +171,12 @@ class ArvadosBase < ActiveRecord::Base true end end - + def links(*args) o = {} o.merge!(args.pop) if args[-1].is_a? Hash o[:link_class] ||= args.shift o[:name] ||= args.shift - o[:head_kind] ||= args.shift - o[:tail_kind] = self.kind o[:tail_uuid] = self.uuid if all_links return all_links.select do |m| @@ -158,6 +195,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, '', { @@ -170,9 +208,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 @@ -195,8 +235,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 @@ -209,6 +255,10 @@ class ArvadosBase < ActiveRecord::Base } end + def class_for_display + self.class.to_s + end + def self.creatable? current_user end @@ -216,7 +266,8 @@ class ArvadosBase < ActiveRecord::Base def editable? (current_user and current_user.is_active and (current_user.is_admin or - current_user.uuid == self.owner_uuid)) + current_user.uuid == self.owner_uuid or + new_record?)) end def attribute_editable?(attr) @@ -227,7 +278,9 @@ class ArvadosBase < ActiveRecord::Base elsif "uuid owner_uuid".index(attr.to_s) or current_user.is_admin current_user.is_admin else - current_user.uuid == self.owner_uuid or current_user.uuid == self.uuid + current_user.uuid == self.owner_uuid or + current_user.uuid == self.uuid or + new_record? end end @@ -261,9 +314,15 @@ class ArvadosBase < ActiveRecord::Base end def friendly_link_name - if self.class.column_names.include? 'name' - self.name - end + (name if self.respond_to? :name) || uuid + end + + def content_summary + self.class_for_display + end + + def selection_label + friendly_link_name end protected