3 class Arvados::V1::CollectionsController < ApplicationController
6 def self.limit_index_columns_read
11 if resource_attrs[:uuid] and (loc = Keep::Locator.parse(resource_attrs[:uuid]))
12 resource_attrs[:portable_data_hash] = loc.to_s
13 resource_attrs.delete :uuid
18 def find_objects_for_index
19 if params[:include_trash] || ['destroy', 'trash'].include?(action_name)
20 @objects = Collection.unscoped.readable_by(*@read_users)
25 def find_object_by_uuid
26 if loc = Keep::Locator.parse(params[:id])
28 if c = Collection.readable_by(*@read_users).where({ portable_data_hash: loc.to_s }).limit(1).first
30 uuid: c.portable_data_hash,
31 portable_data_hash: c.portable_data_hash,
32 manifest_text: c.signed_manifest_text,
42 if @object.is_a? Collection
43 # Omit unsigned_manifest_text
44 @select ||= model_class.selectable_attributes - ["unsigned_manifest_text"]
52 if !@object.is_trashed
53 @object.update_attributes!(trash_at: db_current_time)
55 earliest_delete = (@object.trash_at +
56 Rails.configuration.blob_signature_ttl.seconds)
57 if @object.delete_at > earliest_delete
58 @object.update_attributes!(delete_at: earliest_delete)
64 if !@object.is_trashed
65 @object.update_attributes!(trash_at: db_current_time)
70 def find_collections(visited, sp, &b)
73 sp.class.columns.each do |c|
74 find_collections(visited, sp[c.name.to_sym], &b) if c.name != "log"
78 find_collections(visited, v, &b)
82 find_collections(visited, v, &b)
85 if m = /[a-f0-9]{32}\+\d+/.match(sp)
87 elsif m = Collection.uuid_regex.match(sp)
93 def search_edges(visited, uuid, direction)
94 if uuid.nil? or uuid.empty? or visited[uuid]
98 if loc = Keep::Locator.parse(uuid)
100 return if visited[loc.to_s]
103 logger.debug "visiting #{uuid}"
106 # uuid is a portable_data_hash
107 collections = Collection.readable_by(*@read_users).where(portable_data_hash: loc.to_s)
108 c = collections.limit(2).all
110 visited[loc.to_s] = c[0]
112 name = collections.limit(1).where("name <> ''").first
114 visited[loc.to_s] = {
115 portable_data_hash: c[0].portable_data_hash,
116 name: "#{name.name} + #{collections.count-1} more"
119 visited[loc.to_s] = {
120 portable_data_hash: c[0].portable_data_hash,
126 if direction == :search_up
127 # Search upstream for jobs where this locator is the output of some job
128 Job.readable_by(*@read_users).where(output: loc.to_s).each do |job|
129 search_edges(visited, job.uuid, :search_up)
132 Job.readable_by(*@read_users).where(log: loc.to_s).each do |job|
133 search_edges(visited, job.uuid, :search_up)
135 elsif direction == :search_down
136 if loc.to_s == "d41d8cd98f00b204e9800998ecf8427e+0"
137 # Special case, don't follow the empty collection.
141 # Search downstream for jobs where this locator is in script_parameters
142 Job.readable_by(*@read_users).where(["jobs.script_parameters like ?", "%#{loc.to_s}%"]).each do |job|
143 search_edges(visited, job.uuid, :search_down)
146 Job.readable_by(*@read_users).where(["jobs.docker_image_locator = ?", "#{loc.to_s}"]).each do |job|
147 search_edges(visited, job.uuid, :search_down)
151 # uuid is a regular Arvados UUID
152 rsc = ArvadosModel::resource_class_for_uuid uuid
154 Job.readable_by(*@read_users).where(uuid: uuid).each do |job|
155 visited[uuid] = job.as_api_response
156 if direction == :search_up
157 # Follow upstream collections referenced in the script parameters
158 find_collections(visited, job) do |hash, col_uuid|
159 search_edges(visited, hash, :search_up) if hash
160 search_edges(visited, col_uuid, :search_up) if col_uuid
162 elsif direction == :search_down
163 # Follow downstream job output
164 search_edges(visited, job.output, direction)
167 elsif rsc == Collection
168 if c = Collection.readable_by(*@read_users).where(uuid: uuid).limit(1).first
169 search_edges(visited, c.portable_data_hash, direction)
170 visited[c.portable_data_hash] = c.as_api_response
173 rsc.where(uuid: uuid).each do |r|
174 visited[uuid] = r.as_api_response
179 if direction == :search_up
180 # Search for provenance links pointing to the current uuid
181 Link.readable_by(*@read_users).
182 where(head_uuid: uuid, link_class: "provenance").
184 visited[link.uuid] = link.as_api_response
185 search_edges(visited, link.tail_uuid, direction)
187 elsif direction == :search_down
188 # Search for provenance links emanating from the current uuid
189 Link.readable_by(current_user).
190 where(tail_uuid: uuid, link_class: "provenance").
192 visited[link.uuid] = link.as_api_response
193 search_edges(visited, link.head_uuid, direction)
200 search_edges(visited, @object[:portable_data_hash], :search_up)
201 search_edges(visited, @object[:uuid], :search_up)
207 search_edges(visited, @object[:uuid], :search_down)
208 search_edges(visited, @object[:portable_data_hash], :search_down)
214 def load_limit_offset_order_params *args
216 if action_name == 'index'
217 # Omit manifest_text and unsigned_manifest_text from index results unless expressly selected.
218 @select ||= model_class.selectable_attributes - ["manifest_text", "unsigned_manifest_text"]