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
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
.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
# 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.