X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/b53513423ab948804425424278ac554870864997..64639ed6313f01016da4e0ffd81752dedf9b052b:/services/api/app/controllers/arvados/v1/links_controller.rb diff --git a/services/api/app/controllers/arvados/v1/links_controller.rb b/services/api/app/controllers/arvados/v1/links_controller.rb index 7716a3d5cf..c956bfc9b4 100644 --- a/services/api/app/controllers/arvados/v1/links_controller.rb +++ b/services/api/app/controllers/arvados/v1/links_controller.rb @@ -20,6 +20,42 @@ class Arvados::V1::LinksController < ApplicationController resource_attrs.delete :head_kind resource_attrs.delete :tail_kind + + if resource_attrs[:link_class] == 'permission' && Link::PermLevel[resource_attrs[:name]] + existing = Link. + lock. # select ... for update + where(link_class: 'permission', + tail_uuid: resource_attrs[:tail_uuid], + head_uuid: resource_attrs[:head_uuid], + name: Link::PermLevel.keys).first + if existing + @object = existing + if Link::PermLevel[resource_attrs[:name]] > Link::PermLevel[existing.name] + # upgrade existing permission link to the requested level. + return update + else + # no-op: existing permission is already greater or equal to + # the newly requested permission. + return show + end + end + elsif resource_attrs[:link_class] == 'permission' && + resource_attrs[:name] == 'can_login' && + resource_attrs[:properties].respond_to?(:has_key?) && + resource_attrs[:properties].has_key?(:username) + existing = Link. + lock. # select ... for update + where(link_class: 'permission', + tail_uuid: resource_attrs[:tail_uuid], + head_uuid: resource_attrs[:head_uuid]). + where('properties @> ?', SafeJSON.dump({'username' => resource_attrs[:properties][:username]})). + first + if existing + @object = existing + return show + end + end + super end @@ -38,7 +74,7 @@ class Arvados::V1::LinksController < ApplicationController protected - def find_object_by_uuid + def find_object_by_uuid(with_lock: false) if params[:id] && params[:id].match(/\D/) params[:uuid] = params.delete :id end @@ -49,7 +85,7 @@ class Arvados::V1::LinksController < ApplicationController .where(uuid: params[:uuid]) .first elsif !current_user - super + super(with_lock: with_lock) else # The usual permission-filtering index query is unnecessarily # inefficient, and doesn't match all permission links that @@ -57,11 +93,15 @@ class Arvados::V1::LinksController < ApplicationController # by UUID, then check whether (a) its tail_uuid is the current # user or (b) its head_uuid is an object the current_user # can_manage. - link = Link.unscoped.where(uuid: params[:uuid]).first + model = Link + if with_lock && Rails.configuration.API.LockBeforeUpdate + model = model.lock + end + link = model.unscoped.where(uuid: params[:uuid]).first if link && link.link_class != 'permission' # Not a permission link. Re-fetch using generic # permission-filtering query. - super + super(with_lock: with_lock) elsif link && (current_user.uuid == link.tail_uuid || current_user.can?(manage: link.head_uuid)) # Permission granted.