X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/cd3966ee048de85447418f00869eec59b38fd7b2..6bf9e1a4b5640f3cdd057810f0c9b8a945bb88bd:/services/api/app/models/user.rb diff --git a/services/api/app/models/user.rb b/services/api/app/models/user.rb index 64facaa98e..da7e7b310d 100644 --- a/services/api/app/models/user.rb +++ b/services/api/app/models/user.rb @@ -23,32 +23,33 @@ class User < ArvadosModel validate :must_unsetup_to_deactivate before_update :prevent_privilege_escalation before_update :prevent_inactive_admin - before_update :verify_repositories_empty, :if => Proc.new { |user| - user.username.nil? and user.username_changed? + before_update :verify_repositories_empty, :if => Proc.new { + username.nil? and username_changed? } - before_update :setup_on_activate + after_update :setup_on_activate before_create :check_auto_admin - before_create :set_initial_username, :if => Proc.new { |user| - user.username.nil? and user.email + before_create :set_initial_username, :if => Proc.new { + username.nil? and email } after_create :after_ownership_change after_create :setup_on_activate after_create :add_system_group_permission_link - after_create :auto_setup_new_user, :if => Proc.new { |user| + after_create :auto_setup_new_user, :if => Proc.new { Rails.configuration.Users.AutoSetupNewUsers and - (user.uuid != system_user_uuid) and - (user.uuid != anonymous_user_uuid) + (uuid != system_user_uuid) and + (uuid != anonymous_user_uuid) and + (uuid[0..4] == Rails.configuration.ClusterID) } after_create :send_admin_notifications before_update :before_ownership_change after_update :after_ownership_change after_update :send_profile_created_notification - after_update :sync_repository_names, :if => Proc.new { |user| - (user.uuid != system_user_uuid) and - user.username_changed? and - (not user.username_was.nil?) + after_update :sync_repository_names, :if => Proc.new { + (uuid != system_user_uuid) and + saved_change_to_username? and + (not username_before_last_save.nil?) } before_destroy :clear_permissions after_destroy :remove_self_from_permissions @@ -151,7 +152,7 @@ SELECT 1 FROM #{PERMISSION_VIEW} end def after_ownership_change - if owner_uuid_changed? + if saved_change_to_owner_uuid? update_permissions self.owner_uuid, self.uuid, CAN_MANAGE_PERM end end @@ -160,6 +161,10 @@ SELECT 1 FROM #{PERMISSION_VIEW} MaterializedPermission.where("user_uuid = ? and target_uuid != ?", uuid, uuid).delete_all end + def forget_cached_group_perms + @group_perms = nil + end + def remove_self_from_permissions MaterializedPermission.where("target_uuid = ?", uuid).delete_all check_permissions_against_full_refresh @@ -190,33 +195,78 @@ SELECT user_uuid, target_uuid, perm_level # and perm_hash[:write] are true if this user can read and write # objects owned by group_uuid. def group_permissions(level=1) - group_perms = {} - - user_uuids_subquery = USER_UUIDS_SUBQUERY_TEMPLATE % {user: "$1", perm_level: "$2"} + @group_perms ||= {} + if @group_perms.empty? + user_uuids_subquery = USER_UUIDS_SUBQUERY_TEMPLATE % {user: "$1", perm_level: 1} - ActiveRecord::Base.connection. - exec_query(%{ + ActiveRecord::Base.connection. + exec_query(%{ SELECT target_uuid, perm_level FROM #{PERMISSION_VIEW} - WHERE user_uuid in (#{user_uuids_subquery}) and perm_level >= $2 + WHERE user_uuid in (#{user_uuids_subquery}) and perm_level >= 1 }, - # "name" arg is a query label that appears in logs: - "User.group_permissions", - # "binds" arg is an array of [col_id, value] for '$1' vars: - [[nil, uuid], - [nil, level]]). - rows.each do |group_uuid, max_p_val| - group_perms[group_uuid] = PERMS_FOR_VAL[max_p_val.to_i] + # "name" arg is a query label that appears in logs: + "User.group_permissions", + # "binds" arg is an array of [col_id, value] for '$1' vars: + [[nil, uuid]]). + rows.each do |group_uuid, max_p_val| + @group_perms[group_uuid] = PERMS_FOR_VAL[max_p_val.to_i] + end + end + + case level + when 1 + @group_perms + when 2 + @group_perms.select {|k,v| v[:write] } + when 3 + @group_perms.select {|k,v| v[:manage] } + else + raise "level must be 1, 2 or 3" end - group_perms end # create links - def setup(repo_name: nil, vm_uuid: nil) - repo_perm = create_user_repo_link repo_name - vm_login_perm = create_vm_login_permission_link(vm_uuid, username) if vm_uuid + def setup(repo_name: nil, vm_uuid: nil, send_notification_email: nil) + newly_invited = Link.where(tail_uuid: self.uuid, + head_uuid: all_users_group_uuid, + link_class: 'permission', + name: 'can_read').empty? + + # Add can_read link from this user to "all users" which makes this + # user "invited" group_perm = create_user_group_link + # Add git repo + repo_perm = if (!repo_name.nil? || Rails.configuration.Users.AutoSetupNewUsersWithRepository) and !username.nil? + repo_name ||= "#{username}/#{username}" + create_user_repo_link repo_name + end + + # Add virtual machine + if vm_uuid.nil? and !Rails.configuration.Users.AutoSetupNewUsersWithVmUUID.empty? + vm_uuid = Rails.configuration.Users.AutoSetupNewUsersWithVmUUID + end + + vm_login_perm = if vm_uuid && username + create_vm_login_permission_link(vm_uuid, username) + end + + # Send welcome email + if send_notification_email.nil? + send_notification_email = Rails.configuration.Mail.SendUserSetupNotificationEmail + end + + if newly_invited and send_notification_email and !Rails.configuration.Users.UserSetupMailText.empty? + begin + UserNotifier.account_is_setup(self).deliver_now + rescue => e + logger.warn "Failed to send email to #{self.email}: #{e}" + end + end + + forget_cached_group_perms + return [repo_perm, vm_login_perm, group_perm, self].compact end @@ -241,11 +291,8 @@ SELECT target_uuid, perm_level name: 'can_login').destroy_all # delete "All users" group read permissions for this user - group = Group.where(name: 'All users').select do |g| - g[:uuid].match(/-f+$/) - end.first Link.where(tail_uuid: self.uuid, - head_uuid: group[:uuid], + head_uuid: all_users_group_uuid, link_class: 'permission', name: 'can_read').destroy_all @@ -257,7 +304,9 @@ SELECT target_uuid, perm_level self.prefs = {} # mark the user as inactive + self.is_admin = false # can't be admin and inactive self.is_active = false + forget_cached_group_perms self.save! end @@ -272,10 +321,6 @@ SELECT target_uuid, perm_level self.is_active_was && !self.is_active - group = Group.where(name: 'All users').select do |g| - g[:uuid].match(/-f+$/) - end.first - # When a user is set up, they are added to the "All users" # group. A user that is part of the "All users" group is # allowed to self-activate. @@ -290,7 +335,7 @@ SELECT target_uuid, perm_level # explaining the correct way to deactivate a user. # if Link.where(tail_uuid: self.uuid, - head_uuid: group[:uuid], + head_uuid: all_users_group_uuid, link_class: 'permission', name: 'can_read').any? errors.add :is_active, "cannot be set to false directly, use the 'Deactivate' button on Workbench, or the 'unsetup' API call" @@ -711,11 +756,11 @@ update #{PERMISSION_VIEW} set target_uuid=$1 where target_uuid = $2 # add the user to the 'All users' group def create_user_group_link return (Link.where(tail_uuid: self.uuid, - head_uuid: all_users_group[:uuid], + head_uuid: all_users_group_uuid, link_class: 'permission', name: 'can_read').first or Link.create(tail_uuid: self.uuid, - head_uuid: all_users_group[:uuid], + head_uuid: all_users_group_uuid, link_class: 'permission', name: 'can_read')) end @@ -743,7 +788,8 @@ update #{PERMISSION_VIEW} set target_uuid=$1 where target_uuid = $2 # Automatically setup if is_active flag turns on def setup_on_activate return if [system_user_uuid, anonymous_user_uuid].include?(self.uuid) - if is_active && (new_record? || is_active_changed?) + if is_active && + (new_record? || saved_change_to_is_active? || will_save_change_to_is_active?) setup end end @@ -751,23 +797,12 @@ update #{PERMISSION_VIEW} set target_uuid=$1 where target_uuid = $2 # Automatically setup new user during creation def auto_setup_new_user setup - if username - create_vm_login_permission_link(Rails.configuration.Users.AutoSetupNewUsersWithVmUUID, - username) - repo_name = "#{username}/#{username}" - if Rails.configuration.Users.AutoSetupNewUsersWithRepository and - Repository.where(name: repo_name).first.nil? - repo = Repository.create!(name: repo_name, owner_uuid: uuid) - Link.create!(tail_uuid: uuid, head_uuid: repo.uuid, - link_class: "permission", name: "can_manage") - end - 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'] + if saved_change_to_prefs? + if prefs_before_last_save.andand.empty? || !prefs_before_last_save.andand['profile'] profile_notification_address = Rails.configuration.Users.UserProfileNotificationAddress ProfileNotifier.profile_created(self, profile_notification_address).deliver_now if profile_notification_address and !profile_notification_address.empty? end @@ -782,7 +817,7 @@ update #{PERMISSION_VIEW} set target_uuid=$1 where target_uuid = $2 end def sync_repository_names - old_name_re = /^#{Regexp.escape(username_was)}\// + old_name_re = /^#{Regexp.escape(username_before_last_save)}\// name_sub = "#{username}/" repositories.find_each do |repo| repo.name = repo.name.sub(old_name_re, name_sub)