X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/975b1912434cdd158abcf2d8b882d90c57c4299e..59522bd2b1a628e090d89f71d491b76a0047fdf5:/services/api/app/models/user.rb diff --git a/services/api/app/models/user.rb b/services/api/app/models/user.rb index f1b5c44407..7ae95cad6c 100644 --- a/services/api/app/models/user.rb +++ b/services/api/app/models/user.rb @@ -13,6 +13,8 @@ class User < ArvadosModel before_create :check_auto_admin after_create :add_system_group_permission_link after_create :send_admin_notifications + after_update :send_profile_created_notification + has_many :authorized_keys, :foreign_key => :authorized_user_uuid, :primary_key => :uuid @@ -41,15 +43,23 @@ class User < ArvadosModel end def groups_i_can(verb) - self.group_permissions.select { |uuid, mask| mask[verb] }.keys + my_groups = self.group_permissions.select { |uuid, mask| mask[verb] }.keys + if verb == :read + my_groups << anonymous_group_uuid + end + my_groups end def can?(actions) return true if is_admin actions.each do |action, target| - target_uuid = target - if target.respond_to? :uuid - target_uuid = target.uuid + unless target.nil? + if target.respond_to? :uuid + target_uuid = target.uuid + else + target_uuid = target + target = ArvadosModel.find_by_uuid(target_uuid) + end end next if target_uuid == self.uuid next if (group_permissions[target_uuid] and @@ -71,19 +81,30 @@ class User < ArvadosModel # Return a hash of {group_uuid: perm_hash} where perm_hash[:read] # and perm_hash[:write] are true if this user can read and write # objects owned by group_uuid. + # + # The permission graph is built by repeatedly enumerating all + # permission links reachable from self.uuid, and then calling + # search_permissions def group_permissions Rails.cache.fetch "groups_for_user_#{self.uuid}" do permissions_from = {} todo = {self.uuid => true} done = {} + # Build the equivalence class of permissions starting with + # self.uuid. On each iteration of this loop, todo contains + # the next set of uuids in the permission equivalence class + # to evaluate. while !todo.empty? lookup_uuids = todo.keys lookup_uuids.each do |uuid| done[uuid] = true end todo = {} newgroups = [] + # include all groups owned by the current set of uuids. Group.where('owner_uuid in (?)', lookup_uuids).each do |group| newgroups << [group.owner_uuid, group.uuid, 'can_manage'] end + # add any permission links from the current lookup_uuids to a + # User or Group. Link.where('tail_uuid in (?) and link_class = ? and (head_uuid like ? or head_uuid like ?)', lookup_uuids, 'permission', @@ -132,102 +153,40 @@ class User < ArvadosModel # delete user signatures, login, repo, and vm perms, and mark as inactive def unsetup # delete oid_login_perms for this user - oid_login_perms = Link.where(tail_uuid: self.email, - link_class: 'permission', - name: 'can_login') - oid_login_perms.each do |perm| - Link.delete perm - end + Link.destroy_all(tail_uuid: self.email, + link_class: 'permission', + name: 'can_login') # delete repo_perms for this user - repo_perms = Link.where(tail_uuid: self.uuid, - link_class: 'permission', - name: 'can_write') - repo_perms.each do |perm| - Link.delete perm - end + Link.destroy_all(tail_uuid: self.uuid, + link_class: 'permission', + name: 'can_manage') # delete vm_login_perms for this user - vm_login_perms = Link.where(tail_uuid: self.uuid, - link_class: 'permission', - name: 'can_login') - vm_login_perms.each do |perm| - Link.delete perm - end + Link.destroy_all(tail_uuid: self.uuid, + link_class: 'permission', + name: 'can_login') # delete "All users' group read permissions for this user group = Group.where(name: 'All users').select do |g| g[:uuid].match /-f+$/ end.first - group_perms = Link.where(tail_uuid: self.uuid, - head_uuid: group[:uuid], - link_class: 'permission', - name: 'can_read') - group_perms.each do |perm| - Link.delete perm - end + Link.destroy_all(tail_uuid: self.uuid, + head_uuid: group[:uuid], + link_class: 'permission', + name: 'can_read') # delete any signatures by this user - signed_uuids = Link.where(link_class: 'signature', - tail_uuid: self.uuid) - signed_uuids.each do |sign| - Link.delete sign - end + Link.destroy_all(link_class: 'signature', + tail_uuid: self.uuid) # mark the user as inactive self.is_active = false self.save! end - def owns? object_uuid - return User.find_user_owning(object_uuid).andand.uuid == uuid - end - - def can_manage? object_uuid - is_admin or - owns?(object_uuid) or - has_permission?(:can_manage, object_uuid) - end - protected - # Returns the first User found in the ownership path for obj_uuid. - # If obj_uuid is not owned by any user, returns nil. - # - # TODO(twp): this code largely stolen from - # ArvadosModel::ensure_ownership_path_leads_to_user. See if we can - # refactor these methods to share more code. - # - def self.find_user_owning obj_uuid - uuid_in_path = {obj_uuid => true} - # Walk up the owner_uuid chain for obj_uuid until one of these - # conditions is met: - # - the owner_uuid belongs to the User class - # - no owner_uuid is found (no User owns this object) - # - we discover an ownership cycle (a fatal consistency error) - # - x = obj_uuid - while (owner_class = ArvadosModel.resource_class_for_uuid(x)) != User - begin - if !owner_class.respond_to? :find_by_uuid - raise ActiveRecord::RecordNotFound.new - else - x = owner_class.find_by_uuid(x).owner_uuid - end - rescue ActiveRecord::RecordNotFound => e - # errors.add :owner_uuid, "is not owned by any user: #{e}" - return nil - end - # If there is an ownership cycle, we can conclude that - # no User owns this object. - if uuid_in_path[x] - return nil - end - uuid_in_path[x] = true - end - return owner_class.find_by_uuid(x) - end - def ensure_ownership_path_leads_to_user true end @@ -246,7 +205,7 @@ class User < ArvadosModel def check_auto_admin if User.where("uuid not like '%-000000000000000'").where(:is_admin => true).count == 0 and Rails.configuration.auto_admin_user - if current_user.email == Rails.configuration.auto_admin_user + if self.email == Rails.configuration.auto_admin_user self.is_admin = true self.is_active = true end @@ -340,7 +299,7 @@ class User < ArvadosModel repo_perms = Link.where(tail_uuid: self.uuid, head_uuid: repo[:uuid], link_class: 'permission', - name: 'can_write') + name: 'can_manage') if repo_perms.any? logger.warn "User already has repository access " + repo_perms.collect { |p| p[:uuid] }.inspect @@ -355,7 +314,7 @@ class User < ArvadosModel repo_perm = Link.create(tail_uuid: self.uuid, head_uuid: repo[:uuid], link_class: 'permission', - name: 'can_write') + name: 'can_manage') logger.info { "repo permission: " + repo_perm[:uuid] } return repo_perm end @@ -457,4 +416,15 @@ class User < ArvadosModel AdminNotifier.new_inactive_user(self).deliver end end + + # Send notification if the user saved profile for the first time + def send_profile_created_notification + if self.prefs_changed? + if self.prefs_was.andand.empty? || !self.prefs_was.andand['profile'] + profile_notification_address = Rails.configuration.user_profile_notification_address + ProfileNotifier.profile_created(self, profile_notification_address).deliver if profile_notification_address + end + end + end + end