-require 'assign_uuid'
+require 'has_uuid'
+
class ArvadosModel < ActiveRecord::Base
self.abstract_class = true
before_save :ensure_ownership_path_leads_to_user
before_destroy :ensure_owner_uuid_is_permitted
before_destroy :ensure_permission_to_destroy
-
before_create :update_modified_by_fields
before_update :maybe_update_modified_by_fields
after_create :log_create
# Note: This only returns permission links. It does not account for
# permissions obtained via user.is_admin or
# user.uuid==object.owner_uuid.
- has_many :permissions, :foreign_key => :head_uuid, :class_name => 'Link', :primary_key => :uuid, :conditions => "link_class = 'permission'"
+ has_many :permissions, :foreign_key => :head_uuid, :class_name => 'Link', :primary_key => :uuid, :conditions => "link_class = 'permission'", dependent: :destroy
class PermissionDeniedError < StandardError
def http_status
self.columns.select { |col| col.name == attr.to_s }.first
end
+ # Return nil if current user is not allowed to see the list of
+ # writers. Otherwise, return a list of user_ and group_uuids with
+ # write permission. (If not returning nil, current_user is always in
+ # the list because can_manage permission is needed to see the list
+ # of writers.)
+ def writable_by
+ unless (owner_uuid == current_user.uuid or
+ current_user.is_admin or
+ current_user.groups_i_can(:manage).index(owner_uuid))
+ return nil
+ end
+ [owner_uuid, current_user.uuid] + permissions.collect do |p|
+ if ['can_write', 'can_manage'].index p.name
+ p.tail_uuid
+ end
+ end.compact.uniq
+ end
+
# Return a query with read permissions restricted to the union of of the
# permissions of the members of users_list, i.e. if something is readable by
# any user in users_list, it will be readable in the query returned by this
def ensure_owner_uuid_is_permitted
raise PermissionDeniedError if !current_user
- self.owner_uuid ||= current_user.uuid
+ if respond_to? :owner_uuid=
+ self.owner_uuid ||= current_user.uuid
+ end
if self.owner_uuid_changed?
- if current_user.uuid == self.owner_uuid or
+ if new_record?
+ return true
+ elsif current_user.uuid == self.owner_uuid or
current_user.can? write: self.owner_uuid
# current_user is, or has :write permission on, the new owner
else
- logger.warn "User #{current_user.uuid} tried to change owner_uuid of #{self.class.to_s} #{self.uuid} to #{self.owner_uuid} but does not have permission to write to #{self.owner_uuid}"
+ logger.warn "User #{current_user.uuid} tried to modify #{self.class.to_s} #{self.uuid} but does not have permission to write #{self.owner_uuid_was}"
raise PermissionDeniedError
end
end
- if new_record?
- return true
- elsif current_user.uuid == self.owner_uuid_was or
- current_user.uuid == self.uuid or
- current_user.can? write: self.owner_uuid_was
- # current user is, or has :write permission on, the previous owner
- return true
- else
- logger.warn "User #{current_user.uuid} tried to modify #{self.class.to_s} #{self.uuid} but does not have permission to write #{self.owner_uuid_was}"
- raise PermissionDeniedError
- end
end
def ensure_permission_to_save
def maybe_update_modified_by_fields
update_modified_by_fields if self.changed? or self.new_record?
+ true
end
def update_modified_by_fields
self.modified_at = Time.now
self.modified_by_user_uuid = current_user ? current_user.uuid : nil
self.modified_by_client_uuid = current_api_client ? current_api_client.uuid : nil
+ true
end
def ensure_serialized_attribute_type