All functional tests passing with refactored code.
[arvados.git] / services / api / app / models / user.rb
index 0364c08f5024060c2e3584d7c7047111914d8156..1147589f36fcd5f9f60f3e0835808318c7c04b36 100644 (file)
@@ -30,9 +30,9 @@ class User < ArvadosModel
   end
 
   def is_invited
-    (self.is_active ||
-     Rails.configuration.new_users_are_active ||
-     self.groups_i_can(:read).select { |x| x.match /-f+$/ }.first)
+    !!(self.is_active ||
+       Rails.configuration.new_users_are_active ||
+       self.groups_i_can(:read).select { |x| x.match /-f+$/ }.first)
   end
 
   def groups_i_can(verb)
@@ -40,6 +40,7 @@ class User < ArvadosModel
   end
 
   def can?(actions)
+    return true if is_admin
     actions.each do |action, target|
       target_uuid = target
       if target.respond_to? :uuid
@@ -74,15 +75,22 @@ class User < ArvadosModel
         lookup_uuids = todo.keys
         lookup_uuids.each do |uuid| done[uuid] = true end
         todo = {}
+        newgroups = []
+        Group.where('owner_uuid in (?)', lookup_uuids).each do |group|
+          newgroups << [group.owner_uuid, group.uuid, 'can_manage']
+        end
         Link.where('tail_uuid in (?) and link_class = ? and head_kind = ?',
                    lookup_uuids,
                    'permission',
                    'arvados#group').each do |link|
-          unless done.has_key? link.head_uuid
-            todo[link.head_uuid] = true
+          newgroups << [link.tail_uuid, link.head_uuid, link.name]
+        end
+        newgroups.each do |tail_uuid, head_uuid, perm_name|
+          unless done.has_key? head_uuid
+            todo[head_uuid] = true
           end
           link_permissions = {}
-          case link.name
+          case perm_name
           when 'can_read'
             link_permissions = {read:true}
           when 'can_write'
@@ -90,10 +98,10 @@ class User < ArvadosModel
           when 'can_manage'
             link_permissions = ALL_PERMISSIONS
           end
-          permissions_from[link.tail_uuid] ||= {}
-          permissions_from[link.tail_uuid][link.head_uuid] ||= {}
+          permissions_from[tail_uuid] ||= {}
+          permissions_from[tail_uuid][head_uuid] ||= {}
           link_permissions.each do |k,v|
-            permissions_from[link.tail_uuid][link.head_uuid][k] ||= v
+            permissions_from[tail_uuid][head_uuid][k] ||= v
           end
         end
       end
@@ -101,6 +109,58 @@ class User < ArvadosModel
     end
   end
 
+  def self.setup(user, repo_name, vm_uuid, openid_prefix)
+    # check if default openid_prefix needs to be overridden
+    if !openid_prefix
+      openid_prefix = Rails.configuration.openid_prefix
+    end
+
+    login_perm_props = {identity_url_prefix: openid_prefix}
+
+    if user[:uuid]
+      found = User.find_by_uuid user[:uuid]
+    end
+
+    if !found
+      if !user[:email]
+        raise "No email found in the input. Aborting user creation."
+      end
+      if user.save
+        oid_login_perm = Link.where(tail_uuid: user[:email],
+                                    head_kind: 'arvados#user',
+                                    link_class: 'permission',
+                                    name: 'can_login')
+
+        if [] == oid_login_perm
+          # create openid login permission
+          oid_login_perm = Link.create(link_class: 'permission',
+                                       name: 'can_login',
+                                       tail_kind: 'email',
+                                       tail_uuid: user[:email],
+                                       head_kind: 'arvados#user',
+                                       head_uuid: user[:uuid],
+                                       properties: login_perm_props
+                                      )
+          logger.info { "openid login permission: " + oid_login_perm[:uuid] }
+        end
+      else
+        raise "Save failed"
+      end
+    else
+      user = found
+    end
+
+    user.setup_links(repo_name, vm_uuid, openid_prefix)
+    return user
+  end 
+
+  # create links
+  def setup_links(repo_name, vm_uuid, openid_prefix)
+    create_user_repo_link repo_name
+    create_vm_login_permission_link vm_uuid, repo_name
+    create_user_group_links
+  end 
+
   protected
 
   def permission_to_update
@@ -116,7 +176,7 @@ class User < ArvadosModel
   end
 
   def check_auto_admin
-    if User.where("uuid not like '%-000000000000000'").where(:is_admin => true).count == 0 and not Rails.configuration.auto_admin_user.nil?
+    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
         self.is_admin = true
         self.is_active = true
@@ -169,4 +229,103 @@ class User < ArvadosModel
     upstream_path.delete start
     merged
   end
+
+  def create_user_repo_link(repo_name)
+    if not repo_name
+      logger.warn ("Repository name not given for #{self.uuid}.")
+      return
+    end
+
+    # Check for an existing repository with the same name we're about to use.
+    repo = (repos = Repository.where(name: repo_name)) != nil ? repos.first : nil
+    if repo
+      logger.warn "Repository exists for #{repo_name}: #{repo[:uuid]}."
+
+      # Look for existing repository access for this repo
+      repo_perms = Link.where(tail_uuid: self.uuid,
+                              head_kind: 'arvados#repository',
+                              head_uuid: repo[:uuid],
+                              link_class: 'permission',
+                              name: 'can_write')
+      if [] != repo_perms
+        logger.warn "User already has repository access " + 
+            repo_perms.collect { |p| p[:uuid] }.inspect
+        return
+      end
+    end
+
+    # create repo, if does not already exist
+    repo ||= Repository.create(name: repo_name)
+    logger.info { "repo uuid: " + repo[:uuid] }
+
+    repo_perm = Link.create(tail_kind: 'arvados#user',
+                            tail_uuid: self.uuid,
+                            head_kind: 'arvados#repository',
+                            head_uuid: repo[:uuid],
+                            link_class: 'permission',
+                            name: 'can_write')
+    logger.info { "repo permission: " + repo_perm[:uuid] }
+  end
+
+  # create login permission for the given vm_uuid, if it does not already exist
+  def create_vm_login_permission_link(vm_uuid, repo_name)
+    # Look up the given virtual machine just to make sure it really exists.
+    begin
+      vm = (vms = VirtualMachine.where(uuid: vm_uuid)) != nil ? vms.first : nil
+      if not vm
+        logger.warn "Could not find virtual machine for #{vm_uuid.inspect}"
+        return
+      end
+
+      logger.info { "vm uuid: " + vm[:uuid] }
+
+      login_perm = Link.where(tail_uuid: self.uuid,
+                              head_uuid: vm[:uuid],
+                              head_kind: 'arvados#virtualMachine',
+                              link_class: 'permission',
+                              name: 'can_login')
+      if [] == login_perm
+        login_perm = Link.create(tail_kind: 'arvados#user',
+                                 tail_uuid: self.uuid,
+                                 head_kind: 'arvados#virtualMachine',
+                                 head_uuid: vm[:uuid],
+                                 link_class: 'permission',
+                                 name: 'can_login',
+                                 properties: {username: repo_name})
+        logger.info { "login permission: " + login_perm[:uuid] }
+      end
+    end
+  end
+
+  # add the user to the 'All users' group
+  def create_user_group_links
+    # Look up the "All users" group (we expect uuid *-*-fffffffffffffff).
+    group = Group.where(name: 'All users').select do |g|
+      g[:uuid].match /-f+$/
+    end.first
+
+    if not group
+      logger.warn "No 'All users' group with uuid '*-*-fffffffffffffff'."
+      return
+    else
+      logger.info { "\"All users\" group uuid: " + group[:uuid] }
+
+      group_perm = Link.where(tail_uuid: self.uuid,
+                              head_uuid: group[:uuid],
+                              head_kind: 'arvados#group',
+                              link_class: 'permission',
+                              name: 'can_read')
+
+      if [] == group_perm
+        group_perm = Link.create(tail_kind: 'arvados#user',
+                                 tail_uuid: self.uuid,
+                                 head_kind: 'arvados#group',
+                                 head_uuid: group[:uuid],
+                                 link_class: 'permission',
+                                 name: 'can_read')
+        logger.info { "group permission: " + group_perm[:uuid] }
+      end
+    end
+  end
+
 end