self.abstract_class = true
attr_accessor :attribute_sortkey
+ def self.arvados_api_client
+ ArvadosApiClient.new_or_current
+ end
+
+ def arvados_api_client
+ ArvadosApiClient.new_or_current
+ end
+
def self.uuid_infix_object_kind
@@uuid_infix_object_kind ||=
begin
infix_kind = {}
- $arvados_api_client.discovery[:schemas].each do |name, schema|
+ arvados_api_client.discovery[:schemas].each do |name, schema|
if schema[:uuidPrefix]
infix_kind[schema[:uuidPrefix]] =
'arvados#' + name.to_s.camelcase(:lower)
end
end
- def initialize(*args)
- super(*args)
+ def initialize raw_params={}
+ super self.class.permit_attribute_params(raw_params)
@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
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
+ @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 self.permit_attribute_params raw_params
+ # strong_parameters does not provide security in Workbench: anyone
+ # who can get this far can just as well do a call directly to our
+ # database (Arvados) with the same credentials we use.
+ #
+ # The following permit! is necessary even with
+ # "ActionController::Parameters.permit_all_parameters = true",
+ # because permit_all does not permit nested attributes.
+ ActionController::Parameters.new(raw_params).permit!
+ end
+
+ def self.create raw_params={}
+ super(permit_attribute_params(raw_params))
+ end
+
+ def update_attributes raw_params={}
+ super(self.class.permit_attribute_params(raw_params))
+ end
+
def save
obdata = {}
self.class.columns.each do |col|
if etag
postdata['_method'] = 'PUT'
obdata.delete :uuid
- resp = $arvados_api_client.api(self.class, '/' + uuid, postdata)
+ resp = arvados_api_client.api(self.class, '/' + uuid, postdata)
else
- resp = $arvados_api_client.api(self.class, '', postdata)
+ resp = arvados_api_client.api(self.class, '', postdata)
end
return false if !resp[:etag] || !resp[:uuid]
@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
def destroy
if etag || uuid
postdata = { '_method' => 'DELETE' }
- resp = $arvados_api_client.api(self.class, '/' + uuid, postdata)
+ resp = arvados_api_client.api(self.class, '/' + uuid, postdata)
resp[:etag] && resp[:uuid] && resp
else
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|
ok
end
end
- @links = $arvados_api_client.api Link, '', { _method: 'GET', where: o, eager: true }
- @links = $arvados_api_client.unpack_api_response(@links)
+ @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, '', {
+ res = arvados_api_client.api Link, '', {
_method: 'GET',
where: {
tail_kind: self.kind,
},
eager: true
}
- @all_links = $arvados_api_client.unpack_api_response(res)
+ @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
hash = uuid_or_hash
else
- hash = $arvados_api_client.api(self.class, '/' + uuid_or_hash)
+ hash = arvados_api_client.api(self.class, '/' + uuid_or_hash)
end
hash.each do |k,v|
if self.respond_to?(k.to_s + '=')
end
end
@all_links = nil
+ @new_record = false
self
end
+
+ def to_param
+ uuid
+ end
+
def dup
super.forget_uuid!
end
}
end
+ def class_for_display
+ self.class.to_s
+ end
+
def self.creatable?
current_user
end
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? or
+ (writable_by.include? current_user.uuid rescue false)))
end
def attribute_editable?(attr)
false
elsif not (current_user.andand.is_active)
false
- elsif "uuid owner_uuid".index(attr.to_s) or current_user.is_admin
+ elsif attr == 'uuid'
current_user.is_admin
else
- current_user.uuid == self.owner_uuid or current_user.uuid == self.uuid
+ editable?
end
end
end
resource_class = nil
uuid.match /^[0-9a-z]{5}-([0-9a-z]{5})-[0-9a-z]{15}$/ do |re|
- resource_class ||= $arvados_api_client.
+ resource_class ||= arvados_api_client.
kind_class(self.uuid_infix_object_kind[re[1]])
end
if opts[:referring_object] and
opts[:referring_attr] and
opts[:referring_attr].match /_uuid$/
- resource_class ||= $arvados_api_client.
+ resource_class ||= arvados_api_client.
kind_class(opts[:referring_object].
attributes[opts[:referring_attr].
sub(/_uuid$/, '_kind')])
(name if self.respond_to? :name) || uuid
end
+ def content_summary
+ self.class_for_display
+ end
+
+ def selection_label
+ friendly_link_name
+ end
+
+ def owner
+ ArvadosBase.find(owner_uuid) rescue nil
+ end
+
protected
def forget_uuid!