X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/2dd9e300bfdf3cbce26a625b579b606425fae61c..24c2a73a0ee37438acaa25c93eb6a703e5358036:/app/models/orvos_model.rb diff --git a/app/models/orvos_model.rb b/app/models/orvos_model.rb index 484fbc05c9..262d755426 100644 --- a/app/models/orvos_model.rb +++ b/app/models/orvos_model.rb @@ -7,9 +7,11 @@ class OrvosModel < ActiveRecord::Base attr_protected :modified_by_user attr_protected :modified_by_client attr_protected :modified_at - before_update :permission_to_update + before_create :ensure_permission_to_create + before_update :ensure_permission_to_update before_create :update_modified_by_fields - before_update :update_modified_by_fields + before_update :maybe_update_modified_by_fields + validate :ensure_serialized_attribute_type def self.kind_class(kind) kind.match(/^orvos\#(.+?)(_list|List)?$/)[1].pluralize.classify.constantize rescue nil @@ -20,40 +22,86 @@ class OrvosModel < ActiveRecord::Base re = col.name.match /^(.*)_kind$/ if (re and self.respond_to? re[1].to_sym and - (auuid = self.send(re[1].to_sym)) and + (auuid = self.send((re[1] + '_uuid').to_sym)) and (aclass = self.class.kind_class(self.send(col.name.to_sym))) and (aobject = aclass.where('uuid=?', auuid).first)) - self.send((re[1]+'=').to_sym, aobject) + self.instance_variable_set('@'+re[1], aobject) end end end protected + def ensure_permission_to_create + raise "Permission denied" unless permission_to_create + end + + def permission_to_create + current_user + end + + def ensure_permission_to_update + raise "Permission denied" unless permission_to_update + end + def permission_to_update - return false unless current_user - if self.owner_changed? and self.owner_was != self.uuid - return Metadatum.where(metadata_class: 'permission', - name: 'can_pillage', - tail: self.owner, - head: current_user.uuid).count > 0 + if !current_user + logger.warn "Anonymous user tried to update #{self.class.to_s} #{self.uuid_was}" + return false + end + if self.uuid_changed? + logger.warn "User #{current_user.uuid} tried to change uuid of #{self.class.to_s} #{self.uuid_was} to #{self.uuid}" + return false end - self.owner == current_user.uuid or + return true if current_user.is_admin + if self.owner_changed? and + self.owner_was != current_user.uuid and + 0 == Link.where(link_class: 'permission', + name: 'can_pillage', + tail_uuid: self.owner_was, + head_uuid: current_user.uuid).count + logger.warn "User #{current_user.uuid} tried to change owner of #{self.class.to_s} #{self.uuid} to #{self.owner}" + return false + end + if self.owner_was == current_user.uuid or current_user.is_admin or current_user.uuid == self.uuid or - Metadatum.where(metadata_class: 'permission', - name: 'can_write', - tail: self.owner, - head: current_user.uuid).count > 0 + Link.where(link_class: 'permission', + name: 'can_write', + tail_uuid: self.owner_was, + head_uuid: current_user.uuid).count > 0 + return true + else + logger.warn "User #{current_user.uuid} tried to modify #{self.class.to_s} #{self.uuid} but does not have can_write permission and owner is #{self.owner_was}" + return false + end + end + + def maybe_update_modified_by_fields + update_modified_by_fields if self.changed? end def update_modified_by_fields - if self.changed? - self.created_at ||= Time.now - self.owner ||= current_user.uuid - self.modified_at = Time.now - self.modified_by_user = current_user.uuid - self.modified_by_client = current_api_client ? current_api_client.uuid : nil + self.created_at ||= Time.now + self.owner ||= current_user.uuid if current_user + self.modified_at = Time.now + self.modified_by_user = current_user ? current_user.uuid : nil + self.modified_by_client = current_api_client ? current_api_client.uuid : nil + end + + def ensure_serialized_attribute_type + # Specifying a type in the "serialize" declaration causes rails to + # raise an exception if a different data type is retrieved from + # the database during load(). The validation preventing such + # crash-inducing records from being inserted in the database in + # the first place seems to have been left as an exercise to the + # developer. + self.class.serialized_attributes.each do |colname, attr| + if attr.object_class + unless self.attributes[colname].is_a? attr.object_class + self.errors.add colname.to_sym, "must be a #{attr.object_class.to_s}" + end + end end end end