root_of[g.uuid] == current_user.uuid
end
end
+
+ # helper method to get links for given object or uuid
+ helper_method :links_for_object
+ def links_for_object object_or_uuid
+ raise ArgumentError, 'No input argument' unless object_or_uuid
+ preload_links_for_objects([object_or_uuid])
+ uuid = object_or_uuid.is_a?(String) ? object_or_uuid : object_or_uuid.uuid
+ @all_links_for[uuid] ||= []
+ end
+
+ # helper method to preload links for given objects and uuids
+ helper_method :preload_links_for_objects
+ def preload_links_for_objects objects_and_uuids
+ @all_links_for ||= {}
+
+ raise ArgumentError, 'Argument is not an array' unless objects_and_uuids.is_a? Array
+ return @all_links_for if objects_and_uuids.empty?
+
+ uuids = objects_and_uuids.collect { |x| x.is_a?(String) ? x : x.uuid }
+
+ # if already preloaded for all of these uuids, return
+ if not uuids.select { |x| @all_links_for[x].nil? }.any?
+ return @all_links_for
+ end
+
+ uuids.each do |x|
+ @all_links_for[x] = []
+ end
+
+ # TODO: make sure we get every page of results from API server
+ Link.filter([['head_uuid', 'in', uuids]]).each do |link|
+ @all_links_for[link.head_uuid] << link
+ end
+ @all_links_for
+ end
+
+ # helper method to get a certain number of objects of a specific type
+ # this can be used to replace any uses of: "dataclass.limit(n)"
+ helper_method :get_n_objects_of_class
+ def get_n_objects_of_class dataclass, size
+ @objects_map_for ||= {}
+
+ raise ArgumentError, 'Argument is not a data class' unless dataclass.is_a? Class
+ raise ArgumentError, 'Argument is not a valid limit size' unless (size && size>0)
+
+ # if the objects_map_for has a value for this dataclass, and the
+ # size used to retrieve those objects is equal, return it
+ size_key = "#{dataclass.name}_size"
+ if @objects_map_for[dataclass.name] && @objects_map_for[size_key] &&
+ (@objects_map_for[size_key] == size)
+ return @objects_map_for[dataclass.name]
+ end
+
+ @objects_map_for[size_key] = size
+ @objects_map_for[dataclass.name] = dataclass.limit(size)
+ end
+
+ # helper method to get collections for the given uuid
+ helper_method :collections_for_object
+ def collections_for_object uuid
+ raise ArgumentError, 'No input argument' unless uuid
+ preload_collections_for_objects([uuid])
+ @all_collections_for[uuid] ||= []
+ end
+
+ # helper method to preload collections for the given uuids
+ helper_method :preload_collections_for_objects
+ def preload_collections_for_objects uuids
+ @all_collections_for ||= {}
+
+ raise ArgumentError, 'Argument is not an array' unless uuids.is_a? Array
+ return @all_collections_for if uuids.empty?
+
+ # if already preloaded for all of these uuids, return
+ if not uuids.select { |x| @all_collections_for[x].nil? }.any?
+ return @all_collections_for
+ end
+
+ uuids.each do |x|
+ @all_collections_for[x] = []
+ end
+
+ # TODO: make sure we get every page of results from API server
+ Collection.where(uuid: uuids).each do |collection|
+ @all_collections_for[collection.uuid] << collection
+ end
+ @all_collections_for
+ end
+
+ # helper method to get log collections for the given log
+ helper_method :log_collections_for_object
+ def log_collections_for_object log
+ raise ArgumentError, 'No input argument' unless log
+
+ preload_log_collections_for_objects([log])
+
+ uuid = log
+ fixup = /([a-f0-9]{32}\+\d+)(\+?.*)/.match(log)
+ if fixup && fixup.size>1
+ uuid = fixup[1]
+ end
+
+ @all_log_collections_for[uuid] ||= []
+ end
+
+ # helper method to preload collections for the given uuids
+ helper_method :preload_log_collections_for_objects
+ def preload_log_collections_for_objects logs
+ @all_log_collections_for ||= {}
+
+ raise ArgumentError, 'Argument is not an array' unless logs.is_a? Array
+ return @all_log_collections_for if logs.empty?
+
+ uuids = []
+ logs.each do |log|
+ fixup = /([a-f0-9]{32}\+\d+)(\+?.*)/.match(log)
+ if fixup && fixup.size>1
+ uuids << fixup[1]
+ else
+ uuids << log
+ end
+ end
+
+ # if already preloaded for all of these uuids, return
+ if not uuids.select { |x| @all_log_collections_for[x].nil? }.any?
+ return @all_log_collections_for
+ end
+
+ uuids.each do |x|
+ @all_log_collections_for[x] = []
+ end
+
+ # TODO: make sure we get every page of results from API server
+ Collection.where(uuid: uuids).each do |collection|
+ @all_log_collections_for[collection.uuid] << collection
+ end
+ @all_log_collections_for
+ end
+
+ # helper method to get object of a given dataclass and uuid
+ helper_method :object_for_dataclass
+ def object_for_dataclass dataclass, uuid
+ raise ArgumentError, 'No input argument dataclass' unless (dataclass && uuid)
+ preload_objects_for_dataclass(dataclass, [uuid])
+ @objects_for[uuid]
+ end
+
+ # helper method to preload objects for given dataclass and uuids
+ helper_method :preload_objects_for_dataclass
+ def preload_objects_for_dataclass dataclass, uuids
+ @objects_for ||= {}
+
+ raise ArgumentError, 'Argument is not a data class' unless dataclass.is_a? Class
+ raise ArgumentError, 'Argument is not an array' unless uuids.is_a? Array
+
+ return @objects_for if uuids.empty?
+
+ # if already preloaded for all of these uuids, return
+ if not uuids.select { |x| @objects_for[x].nil? }.any?
+ return @objects_for
+ end
+
+ dataclass.where(uuid: uuids).each do |obj|
+ @objects_for[obj.uuid] = obj
+ end
+ @objects_for
+ end
+
end
link_name = attrvalue.friendly_link_name
else
begin
- link_name = resource_class.find(link_uuid).friendly_link_name
+ if resource_class.name == 'Collection'
+ link_name = collections_for_object(link_uuid).andand.first.andand.friendly_link_name
+ else
+ link_name = object_for_dataclass(resource_class, link_uuid).friendly_link_name
+ end
rescue RuntimeError
# If that lookup failed, the link will too. So don't make one.
return attrvalue
link_name = "#{resource_class.to_s}: #{link_name}"
end
if !opts[:no_tags] and resource_class == Collection
- Link.where(head_uuid: link_uuid, link_class: ["tag", "identifier"]).each do |tag|
- link_name += ' <span class="label label-info">' + html_escape(tag.name) + '</span>'
+ links_for_object(link_uuid).each do |tag|
+ if tag.link_class.in? ["tag", "identifier"]
+ link_name += ' <span class="label label-info">' + html_escape(tag.name) + '</span>'
+ end
end
end
if opts[:thumbnail] and resource_class == Collection
# add an image thumbnail if the collection consists of a single image file.
- Collection.where(uuid: link_uuid).each do |c|
+ collections_for_object(link_uuid).each do |c|
if c.files.length == 1 and CollectionsHelper::is_image c.files.first[1]
link_name += " "
link_name += image_tag "#{url_for c}/#{CollectionsHelper::file_path c.files.first}", style: "height: 4em; width: auto"
dn += '[value]'
end
+ # preload data
+ preload_uuids = []
+ items = []
selectables = []
+
attrtext = attrvalue
if dataclass and dataclass.is_a? Class
+ objects = get_n_objects_of_class dataclass, 10
+ objects.each do |item|
+ items << item
+ preload_uuids << item.uuid
+ end
if attrvalue and !attrvalue.empty?
- Link.where(head_uuid: attrvalue, link_class: ["tag", "identifier"]).each do |tag|
- attrtext += " [#{tag.name}]"
+ preload_uuids << attrvalue
+ end
+ preload_links_for_objects preload_uuids
+
+ if attrvalue and !attrvalue.empty?
+ links_for_object(attrvalue).each do |link|
+ if link.link_class.in? ["tag", "identifier"]
+ attrtext += " [#{tag.name}]"
+ end
end
selectables.append({name: attrtext, uuid: attrvalue, type: dataclass.to_s})
end
- #dataclass.where(uuid: attrvalue).each do |item|
- # selectables.append({name: item.uuid, uuid: item.uuid, type: dataclass.to_s})
- #end
itemuuids = []
- dataclass.limit(10).each do |item|
+ items.each do |item|
itemuuids << item.uuid
selectables.append({name: item.uuid, uuid: item.uuid, type: dataclass.to_s})
end
- Link.where(head_uuid: itemuuids, link_class: ["tag", "identifier"]).each do |tag|
- selectables.each do |selectable|
- if selectable['uuid'] == tag.head_uuid
- selectable['name'] += ' [' + tag.name + ']'
+
+ itemuuids.each do |itemuuid|
+ links_for_object(itemuuid).each do |link|
+ if link.link_class.in? ["tag", "identifier"]
+ selectables.each do |selectable|
+ if selectable['uuid'] == tag.head_uuid
+ selectable['name'] += ' [' + tag.name + ']'
+ end
+ end
end
end
end
--- /dev/null
+require 'test_helper'
+
+class ApplicationControllerTest < ActionController::TestCase
+
+ setup do
+ @user_dataclass = ArvadosBase.resource_class_for_uuid(api_fixture('users')['active']['uuid'])
+ end
+
+ test "links for object" do
+ use_token :active
+
+ ac = ApplicationController.new
+
+ link_head_uuid = api_fixture('links')['foo_file_readable_by_active']['head_uuid']
+
+ links = ac.send :links_for_object, link_head_uuid
+
+ assert links, 'Expected links'
+ assert links.is_a?(Array), 'Expected an array'
+ assert links.size > 0, 'Expected at least one link'
+ assert links[0][:uuid], 'Expected uuid for the head_link'
+ end
+
+ test "preload links for objects and uuids" do
+ use_token :active
+
+ ac = ApplicationController.new
+
+ link1_head_uuid = api_fixture('links')['foo_file_readable_by_active']['head_uuid']
+ link2_uuid = api_fixture('links')['bar_file_readable_by_active']['uuid']
+ link3_head_uuid = api_fixture('links')['bar_file_readable_by_active']['head_uuid']
+
+ link2_object = User.find(api_fixture('users')['active']['uuid'])
+ link2_object_uuid = link2_object['uuid']
+
+ uuids = [link1_head_uuid, link2_object, link3_head_uuid]
+ links = ac.send :preload_links_for_objects, uuids
+
+ assert links, 'Expected links'
+ assert links.is_a?(Hash), 'Expected a hash'
+ assert links.size == 3, 'Expected two objects in the preloaded links hash'
+ assert links[link1_head_uuid], 'Expected links for the passed in link head_uuid'
+ assert links[link2_object_uuid], 'Expected links for the passed in object uuid'
+ assert links[link3_head_uuid], 'Expected links for the passed in link head_uuid'
+
+ # invoke again for this same input. this time, the preloaded data will be returned
+ links = ac.send :preload_links_for_objects, uuids
+ assert links, 'Expected links'
+ assert links.is_a?(Hash), 'Expected a hash'
+ assert links.size == 3, 'Expected two objects in the preloaded links hash'
+ assert links[link1_head_uuid], 'Expected links for the passed in link head_uuid'
+ end
+
+ [ [:preload_links_for_objects, [] ],
+ [:preload_collections_for_objects, [] ],
+ [:preload_log_collections_for_objects, [] ],
+ [:preload_objects_for_dataclass, [] ],
+ ].each do |input|
+ test "preload data for empty array input #{input}" do
+ use_token :active
+
+ ac = ApplicationController.new
+
+ if input[0] == :preload_objects_for_dataclass
+ objects = ac.send input[0], @user_dataclass, input[1]
+ else
+ objects = ac.send input[0], input[1]
+ end
+
+ assert objects, 'Expected objects'
+ assert objects.is_a?(Hash), 'Expected a hash'
+ assert objects.size == 0, 'Expected no objects in the preloaded hash'
+ end
+ end
+
+ [ [:preload_links_for_objects, 'input not an array'],
+ [:preload_links_for_objects, nil],
+ [:links_for_object, nil],
+ [:preload_collections_for_objects, 'input not an array'],
+ [:preload_collections_for_objects, nil],
+ [:collections_for_object, nil],
+ [:preload_log_collections_for_objects, 'input not an array'],
+ [:preload_log_collections_for_objects, nil],
+ [:log_collections_for_object, nil],
+ [:preload_objects_for_dataclass, 'input not an array'],
+ [:preload_objects_for_dataclass, nil],
+ [:object_for_dataclass, 'some_dataclass', nil],
+ [:object_for_dataclass, nil, 'some_uuid'],
+ ].each do |input|
+ test "preload data for wrong type input #{input}" do
+ use_token :active
+
+ ac = ApplicationController.new
+
+ if input[0] == :object_for_dataclass
+ assert_raise ArgumentError do
+ ac.send input[0], input[1], input[2]
+ end
+ else
+ assert_raise ArgumentError do
+ ac.send input[0], input[1]
+ end
+ end
+ end
+ end
+
+ [ [:links_for_object, 'no-such-uuid' ],
+ [:collections_for_object, 'no-such-uuid' ],
+ [:log_collections_for_object, 'no-such-uuid' ],
+ [:object_for_dataclass, 'no-such-uuid' ],
+ ].each do |input|
+ test "get data for no such uuid #{input}" do
+ use_token :active
+
+ ac = ApplicationController.new
+
+ if input[0] == :object_for_dataclass
+ object = ac.send input[0], @user_dataclass, input[1]
+ assert_not object, 'Expected no object'
+ else
+ objects = ac.send input[0], input[1]
+ assert objects, 'Expected objects'
+ assert objects.is_a?(Array), 'Expected a array'
+ end
+ end
+ end
+
+ test "get 10 objects of data class user" do
+ use_token :active
+
+ ac = ApplicationController.new
+
+ objects = ac.send :get_n_objects_of_class, @user_dataclass, 10
+
+ assert objects, 'Expected objects'
+ assert objects.is_a?(ArvadosResourceList), 'Expected an ArvadosResourceList'
+
+ first_object = objects.first
+ assert first_object, 'Expected at least one object'
+ assert_equal 'User', first_object.class.name, 'Expected user object'
+
+ # invoke it again. this time, the preloaded info will be returned
+ objects = ac.send :get_n_objects_of_class, @user_dataclass, 10
+ assert objects, 'Expected objects'
+ assert_equal 'User', objects.first.class.name, 'Expected user object'
+ end
+
+ [ ['User', 10],
+ [nil, 10],
+ [@user_dataclass, 0],
+ [@user_dataclass, -1],
+ [@user_dataclass, nil] ].each do |input|
+ test "get_n_objects for incorrect input #{input}" do
+ use_token :active
+
+ ac = ApplicationController.new
+
+ assert_raise ArgumentError do
+ ac.send :get_n_objects_of_class, input[0], input[1]
+ end
+ end
+ end
+
+ test "collections for object" do
+ use_token :active
+
+ ac = ApplicationController.new
+
+ uuid = api_fixture('collections')['foo_file']['uuid']
+
+ collections = ac.send :collections_for_object, uuid
+
+ assert collections, 'Expected collections'
+ assert collections.is_a?(Array), 'Expected an array'
+ assert collections.size == 1, 'Expected one collection object'
+ assert_equal collections[0][:uuid], uuid, 'Expected uuid not found in collections'
+ end
+
+ test "preload collections for given uuids" do
+ use_token :active
+
+ ac = ApplicationController.new
+
+ uuid1 = api_fixture('collections')['foo_file']['uuid']
+ uuid2 = api_fixture('collections')['bar_file']['uuid']
+
+ uuids = [uuid1, uuid2]
+ collections = ac.send :preload_collections_for_objects, uuids
+
+ assert collections, 'Expected collection'
+ assert collections.is_a?(Hash), 'Expected a hash'
+ assert collections.size == 2, 'Expected two objects in the preloaded collection hash'
+ assert collections[uuid1], 'Expected collections for the passed in uuid'
+ assert_equal collections[uuid1].size, 1, 'Expected one collection for the passed in uuid'
+ assert collections[uuid2], 'Expected collections for the passed in uuid'
+ assert_equal collections[uuid2].size, 1, 'Expected one collection for the passed in uuid'
+
+ # invoke again for this same input. this time, the preloaded data will be returned
+ collections = ac.send :preload_collections_for_objects, uuids
+ assert collections, 'Expected collection'
+ assert collections.is_a?(Hash), 'Expected a hash'
+ assert collections.size == 2, 'Expected two objects in the preloaded collection hash'
+ assert collections[uuid1], 'Expected collections for the passed in uuid'
+ end
+
+ test "log collections for object" do
+ use_token :active
+
+ ac = ApplicationController.new
+
+ uuid = api_fixture('logs')['log4']['object_uuid']
+
+ collections = ac.send :log_collections_for_object, uuid
+
+ assert collections, 'Expected collections'
+ assert collections.is_a?(Array), 'Expected an array'
+ assert collections.size == 1, 'Expected one collection object'
+ assert_equal collections[0][:uuid], uuid, 'Expected uuid not found in collections'
+ end
+
+ test "preload log collections for given uuids" do
+ use_token :active
+
+ ac = ApplicationController.new
+
+ uuid1 = api_fixture('logs')['log4']['object_uuid']
+ uuid2 = api_fixture('collections')['bar_file']['uuid']
+
+ uuids = [uuid1, uuid2]
+ collections = ac.send :preload_log_collections_for_objects, uuids
+
+ assert collections, 'Expected collection'
+ assert collections.is_a?(Hash), 'Expected a hash'
+ assert collections.size == 2, 'Expected two objects in the preloaded collection hash'
+ assert collections[uuid1], 'Expected collections for the passed in uuid'
+ assert_equal collections[uuid1].size, 1, 'Expected one collection for the passed in uuid'
+ assert collections[uuid2], 'Expected collections for the passed in uuid'
+ assert_equal collections[uuid2].size, 1, 'Expected one collection for the passed in uuid'
+
+ # invoke again for this same input. this time, the preloaded data will be returned
+ collections = ac.send :preload_log_collections_for_objects, uuids
+ assert collections, 'Expected collection'
+ assert collections.is_a?(Hash), 'Expected a hash'
+ assert collections.size == 2, 'Expected two objects in the preloaded collection hash'
+ assert collections[uuid1], 'Expected collections for the passed in uuid'
+ end
+
+ test "object for dataclass" do
+ use_token :active
+
+ ac = ApplicationController.new
+
+ dataclass = ArvadosBase.resource_class_for_uuid(api_fixture('jobs')['running']['uuid'])
+ uuid = api_fixture('jobs')['running']['uuid']
+
+ obj = ac.send :object_for_dataclass, dataclass, uuid
+
+ assert obj, 'Expected object'
+ assert 'Job', obj.class
+ assert_equal uuid, obj['uuid'], 'Expected uuid not found'
+ assert_equal api_fixture('jobs')['running']['script_version'], obj['script_version'],
+ 'Expected script_version not found'
+ end
+
+ test "preload objects for dataclass" do
+ use_token :active
+
+ ac = ApplicationController.new
+
+ dataclass = ArvadosBase.resource_class_for_uuid(api_fixture('jobs')['running']['uuid'])
+
+ uuid1 = api_fixture('jobs')['running']['uuid']
+ uuid2 = api_fixture('jobs')['running_cancelled']['uuid']
+
+ uuids = [uuid1, uuid2]
+ users = ac.send :preload_objects_for_dataclass, dataclass, uuids
+
+ assert users, 'Expected objects'
+ assert users.is_a?(Hash), 'Expected a hash'
+
+ assert users.size == 2, 'Expected two objects in the preloaded hash'
+ assert users[uuid1], 'Expected user object for the passed in uuid'
+ assert users[uuid2], 'Expected user object for the passed in uuid'
+
+ # invoke again for this same input. this time, the preloaded data will be returned
+ users = ac.send :preload_objects_for_dataclass, dataclass, uuids
+ assert users, 'Expected objects'
+ assert users.is_a?(Hash), 'Expected a hash'
+ assert users.size == 2, 'Expected two objects in the preloaded hash'
+
+ # invoke again for this with one more uuid
+ uuids << api_fixture('jobs')['foobar']['uuid']
+ users = ac.send :preload_objects_for_dataclass, dataclass, uuids
+ assert users, 'Expected objects'
+ assert users.is_a?(Hash), 'Expected a hash'
+ assert users.size == 3, 'Expected two objects in the preloaded hash'
+ end
+
+end