3 class Arvados::V1::CollectionsController < ApplicationController
5 if resource_attrs[:uuid] and (loc = Keep::Locator.parse(resource_attrs[:uuid]))
6 resource_attrs[:portable_data_hash] = loc.to_s
7 resource_attrs.delete :uuid
12 def find_object_by_uuid
13 if loc = Keep::Locator.parse(params[:id])
15 if c = Collection.readable_by(*@read_users).where({ portable_data_hash: loc.to_s }).limit(1).first
17 uuid: c.portable_data_hash,
18 portable_data_hash: c.portable_data_hash,
19 manifest_text: c.signed_manifest_text,
29 if @object.is_a? Collection
40 def find_collections(visited, sp, &b)
43 sp.class.columns.each do |c|
44 find_collections(visited, sp[c.name.to_sym], &b) if c.name != "log"
48 find_collections(visited, v, &b)
52 find_collections(visited, v, &b)
55 if m = /[a-f0-9]{32}\+\d+/.match(sp)
57 elsif m = /[0-9a-z]{5}-4zz18-[0-9a-z]{15}/.match(sp)
63 def search_edges(visited, uuid, direction)
64 if uuid.nil? or uuid.empty? or visited[uuid]
68 if loc = Keep::Locator.parse(uuid)
70 return if visited[loc.to_s]
73 logger.debug "visiting #{uuid}"
76 # uuid is a portable_data_hash
77 collections = Collection.readable_by(*@read_users).where(portable_data_hash: loc.to_s)
78 c = collections.limit(2).all
80 visited[loc.to_s] = c[0]
82 name = collections.limit(1).where("name <> ''").first
85 portable_data_hash: c[0].portable_data_hash,
86 name: "#{name.name} + #{collections.count-1} more"
90 portable_data_hash: c[0].portable_data_hash,
96 if direction == :search_up
97 # Search upstream for jobs where this locator is the output of some job
98 Job.readable_by(*@read_users).where(output: loc.to_s).each do |job|
99 search_edges(visited, job.uuid, :search_up)
102 Job.readable_by(*@read_users).where(log: loc.to_s).each do |job|
103 search_edges(visited, job.uuid, :search_up)
105 elsif direction == :search_down
106 if loc.to_s == "d41d8cd98f00b204e9800998ecf8427e+0"
107 # Special case, don't follow the empty collection.
111 # Search downstream for jobs where this locator is in script_parameters
112 Job.readable_by(*@read_users).where(["jobs.script_parameters like ?", "%#{loc.to_s}%"]).each do |job|
113 search_edges(visited, job.uuid, :search_down)
116 Job.readable_by(*@read_users).where(["jobs.docker_image_locator = ?", "#{loc.to_s}"]).each do |job|
117 search_edges(visited, job.uuid, :search_down)
121 # uuid is a regular Arvados UUID
122 rsc = ArvadosModel::resource_class_for_uuid uuid
124 Job.readable_by(*@read_users).where(uuid: uuid).each do |job|
125 visited[uuid] = job.as_api_response
126 if direction == :search_up
127 # Follow upstream collections referenced in the script parameters
128 find_collections(visited, job) do |hash, uuid|
129 search_edges(visited, hash, :search_up) if hash
130 search_edges(visited, uuid, :search_up) if uuid
132 elsif direction == :search_down
133 # Follow downstream job output
134 search_edges(visited, job.output, direction)
137 elsif rsc == Collection
138 if c = Collection.readable_by(*@read_users).where(uuid: uuid).limit(1).first
139 search_edges(visited, c.portable_data_hash, direction)
140 visited[c.portable_data_hash] = c.as_api_response
143 rsc.where(uuid: uuid).each do |r|
144 visited[uuid] = r.as_api_response
149 if direction == :search_up
150 # Search for provenance links pointing to the current uuid
151 Link.readable_by(*@read_users).
152 where(head_uuid: uuid, link_class: "provenance").
154 visited[link.uuid] = link.as_api_response
155 search_edges(visited, link.tail_uuid, direction)
157 elsif direction == :search_down
158 # Search for provenance links emanating from the current uuid
159 Link.readable_by(current_user).
160 where(tail_uuid: uuid, link_class: "provenance").
162 visited[link.uuid] = link.as_api_response
163 search_edges(visited, link.head_uuid, direction)
170 search_edges(visited, @object[:portable_data_hash], :search_up)
171 search_edges(visited, @object[:uuid], :search_up)
177 search_edges(visited, @object[:uuid], :search_down)
178 search_edges(visited, @object[:portable_data_hash], :search_down)
184 def load_limit_offset_order_params *args
185 if action_name == 'index'
186 # Omit manifest_text from index results unless expressly selected.
187 @select ||= model_class.api_accessible_attributes(:user).
188 map { |attr_spec| attr_spec.first.to_s } - ["manifest_text"]