1 class Arvados::V1::CollectionsController < ApplicationController
3 # Collections are owned by system_user. Creating a collection has
4 # two effects: The collection is added if it doesn't already
5 # exist, and a "permission" Link is added (if one doesn't already
6 # exist) giving the current user (or specified owner_uuid)
7 # permission to read it.
8 owner_uuid = resource_attrs.delete(:owner_uuid) || current_user.uuid
9 owner_kind = if owner_uuid.match(/-(\w+)-/)[1] == User.uuid_prefix
14 unless current_user.can? write: owner_uuid
15 logger.warn "User #{current_user.andand.uuid} tried to set collection owner_uuid to #{owner_uuid}"
16 raise ArvadosModel::PermissionDeniedError
19 @object = model_class.new resource_attrs.reject { |k,v| k == :owner_uuid }
22 rescue ActiveRecord::RecordNotUnique
23 logger.debug resource_attrs.inspect
24 if resource_attrs[:manifest_text] and resource_attrs[:uuid]
25 @existing_object = model_class.
26 where('uuid=? and manifest_text=?',
27 resource_attrs[:uuid],
28 resource_attrs[:manifest_text]).
30 @object = @existing_object || @object
36 owner_uuid: owner_uuid,
37 link_class: 'permission',
39 head_kind: 'arvados#collection',
40 head_uuid: @object.uuid,
41 tail_kind: owner_kind,
44 ActiveRecord::Base.transaction do
45 if Link.where(link_attrs).empty?
46 Link.create! link_attrs
55 render json: @object.as_api_response(:with_data)
58 def collection_uuid(uuid)
59 m = /([a-f0-9]{32}(\+[0-9]+)?)(\+.*)?/.match(uuid)
67 def script_param_edges(visited, sp)
71 script_param_edges(visited, v)
75 script_param_edges(visited, v)
79 m = collection_uuid(sp)
81 generate_provenance_edges(visited, m)
86 def generate_provenance_edges(visited, uuid)
87 m = collection_uuid(uuid)
90 if not uuid or uuid.empty? or visited[uuid]
94 logger.debug "visiting #{uuid}"
97 # uuid is a collection
98 Collection.readable_by(current_user).where(uuid: uuid).each do |c|
99 visited[uuid] = c.as_api_response
100 visited[uuid][:files] = []
102 visited[uuid][:files] << f
106 Job.readable_by(current_user).where(output: uuid).each do |job|
107 generate_provenance_edges(visited, job.uuid)
110 Job.readable_by(current_user).where(log: uuid).each do |job|
111 generate_provenance_edges(visited, job.uuid)
115 # uuid is something else
116 rsc = ArvadosModel::resource_class_for_uuid uuid
118 Job.readable_by(current_user).where(uuid: uuid).each do |job|
119 visited[uuid] = job.as_api_response
120 script_param_edges(visited, job.script_parameters)
123 rsc.where(uuid: uuid).each do |r|
124 visited[uuid] = r.as_api_response
129 Link.readable_by(current_user).
130 where(head_uuid: uuid, link_class: "provenance").
132 visited[link.uuid] = link.as_api_response
133 generate_provenance_edges(visited, link.tail_uuid)
136 #puts "finished #{uuid}"
141 generate_provenance_edges(visited, @object[:uuid])
145 def generate_used_by_edges(visited, uuid)
146 m = collection_uuid(uuid)
149 if not uuid or uuid.empty? or visited[uuid]
153 logger.debug "visiting #{uuid}"
156 # uuid is a collection
157 Collection.readable_by(current_user).where(uuid: uuid).each do |c|
158 visited[uuid] = c.as_api_response
159 visited[uuid][:files] = []
161 visited[uuid][:files] << f
165 if uuid == "d41d8cd98f00b204e9800998ecf8427e+0"
166 # special case for empty collection
170 Job.readable_by(current_user).where(["jobs.script_parameters like ?", "%#{uuid}%"]).each do |job|
171 generate_used_by_edges(visited, job.uuid)
175 # uuid is something else
176 rsc = ArvadosModel::resource_class_for_uuid uuid
178 Job.readable_by(current_user).where(uuid: uuid).each do |job|
179 visited[uuid] = job.as_api_response
180 generate_used_by_edges(visited, job.output)
183 rsc.where(uuid: uuid).each do |r|
184 visited[uuid] = r.as_api_response
189 Link.readable_by(current_user).
190 where(tail_uuid: uuid, link_class: "provenance").
192 visited[link.uuid] = link.as_api_response
193 generate_used_by_edges(visited, link.head_uuid)
196 #puts "finished #{uuid}"
201 generate_used_by_edges(visited, @object[:uuid])
206 def find_object_by_uuid
208 if !@object and !params[:uuid].match(/^[0-9a-f]+\+\d+$/)
209 # Normalize the given uuid and search again.
210 hash_part = params[:uuid].match(/^([0-9a-f]*)/)[1]
211 collection = Collection.where('uuid like ?', hash_part + '+%').first
213 # We know the collection exists, and what its real uuid is in
214 # the database. Now, throw out @objects and repeat the usual
215 # lookup procedure. (Returning the collection at this point
216 # would bypass permission checks.)
218 @where = { uuid: collection.uuid }
219 find_objects_for_index
220 @object = @objects.first