add role at all of user's currnet sites if site is not specified
[plcapi.git] / PLC / Persons.py
index 518f53c..8170a71 100644 (file)
@@ -15,11 +15,10 @@ import crypt
 from PLC.Faults import *
 from PLC.Debug import log
 from PLC.Parameter import Parameter, Mixed
-from PLC.Table import Row, Table
+from PLC.Messages import Message, Messages
 from PLC.Roles import Role, Roles
 from PLC.Keys import Key, Keys
-from PLC.Messages import Message, Messages
-from PLC.Storage.AlchemyObj import AlchemyObj
+from PLC.Storage.AlchemyObject import AlchemyObj
 
 class Person(AlchemyObj):
     """
@@ -28,8 +27,10 @@ class Person(AlchemyObj):
     dict. Commit to the database with sync().
     """
 
+    tablename = 'persons'
+
     fields = {
-        'person_id': Parameter(int, "User identifier"),
+        'person_id': Parameter(int, "User identifier", primary_key=True),
         'keystone_id': Parameter(int, "Keystone User identifier"),
         'first_name': Parameter(str, "Given name", max = 128),
         'last_name': Parameter(str, "Surname", max = 128),
@@ -90,7 +91,7 @@ class Person(AlchemyObj):
             return True
 
         if 'pi' in self['roles']:
-            if set(self['tenants']).intersection(person['tenants']):
+            if set(self['site_ids']).intersection(person['site_ids']):
                 # non-admin users cannot update a person who is neither a PI or ADMIN
                 return (not set(['pi','admin']).intersection(person['roles']))
 
@@ -118,20 +119,61 @@ class Person(AlchemyObj):
 
         return False
 
-    #add_role = Row.add_object(Role, 'person_role')
-    #remove_role = Row.remove_object(Role, 'person_role')
+    def add_role(self, role_name, login_base=None):
+        user = self.api.client_shell.keystone.users.find(id=self['keystone_id'])
+        roles = Roles(self.api, {'name': role_name})
+        if not roles:
+            raise PLCInvalidArgument, "Role %s not found" % role_name 
+        role = roles[0]
+      
+        if login_base:
+            # add role at the requested site
+            tenant = self.api.client_shell.keystone.tenants.find(name=login_base) 
+            self.api.client_shell.keystone.roles.add_user_role(user, role, tenant)
+        else:
+            from PLC.Sites import Sites
+            # add role to at all of users sites
+            if not self['site_ids']:
+                raise PLCInvalidArgument, "Cannot add role unless user already belongs to a site or a valid site is specified"
+            for site_id in self['site_ids']:
+                sites = Sites(self.api, {'site_id': site_id})
+                site = sites[0]
+                tenant = self.api.client_shell.keystone.tenants.find(id=site['tenant_id'])
+                self.api.client_shell.keystone.roles.add_user_role(user, role, tenant)
+    
+    def remove_role(self, role_name, login_base=None):
+        user = self.api.client_shell.keystone.users.find(id=self['keystone_id'])
+        roles = Roles(self.api, {'name': role_name})
+        if not roles:
+            raise PLCInvalidArgument, "Role %s not found" % role_name
+        role = roles[0]
+
+        if login_base:
+            # add role at the requested site
+            tenant = self.api.client_shell.keystone.tenants.find(name=login_base)
+            self.api.client_shell.keystone.roles.add_user_role(user, role, tenant)
+        else:
+            from PLC.Sites import Sites
+            # add role to at all of users sites
+            if not self['site_ids']:
+                raise PLCInvalidArgument, "Cannot add role unless user already belongs to a site or a valid site
+ is specified"
+            for site_id in self['site_ids']:
+                sites = Sites(self.api, {'site_id': site_id})
+                site = sites[0]
+                tenant = self.api.client_shell.keystone.tenants.find(id=site['tenant_id'])
+                self.api.client_shell.keystone.roles.remove_user_role(user, role, tenant)
 
     #add_key = Row.add_object(Key, 'person_key')
     #remove_key = Row.remove_object(Key, 'person_key')
 
-    def sync(self, insert=False, validate=True):
-        NovaObject.sync(self, insert, validate)
+    def sync(self, commit=True, validate=True):
+        AlchemyObj.sync(self, commit=commit, validate=validate)
         nova_fields = ['enabled', 'email', 'password']
-
         nova_can_update = lambda (field, value): field in nova_fields
         nova_person = dict(filter(nova_can_update, self.items()))
         nova_person['name'] = "%s %s" % (self.get('first_name', ''), self.get('last_name', ''))  
-        if insert == True or 'person_id' not in self:
+        if 'person_id' not in self:
             self.object = self.api.client_shell.keystone.users.create(**self)
             self['keystone_id'] = self.object.id
             AlchemyObj.insert(self, dict(self))
@@ -141,21 +183,20 @@ class Person(AlchemyObj):
         
 
     def delete(self):
+        assert 'person_id' in self
+        assert 'keystone_id' in self
+
+        # delete keystone record
+        nova_user = self.api.client_shell.keystone.users.find(id=self['keystone_id'])
+        self.api.client_shell.keystone.users.delete(nova_user)
+
         # delete relationships
         SlicePerson().delete.filter({'person_id': self['person_id']})
 
-        # delete nova object
-        user = self.api.client_shell.keystone.users.find(**self)
-        self.api.client_shell.keystone.users.delete(user)
+        # delete person
         AlchemyObj.delete(self, dict(self))
 
  
-    def get_roles(self):
-        roles = []
-        if self.tenant:
-            roles = self.api.client_shell.keystone.roles.roles_for_user(self.object, self.tenant)
-        return [role.name for role in roles] 
-
     def get_tenants_ids(self):
         tenants = []
         if self.tenantId:
@@ -177,8 +218,6 @@ class Persons(list):
             #persons = self.api.client_shell.keystone.users.findall()
             persons = Person().select()
         elif isinstance(person_filter, (list, tuple, set)):
-            #persons = self.api.client_shell.keystone.users.findall()
-            #persons = [person for person in persons if person.id in person_filter]
             ints = filter(lambda x: isinstance(x, (int, long)), person_filter)
             strs = filter(lambda x: isinstance(x, StringTypes), person_filter)
             person_filter = {'person_id': ints, 'email': strs}
@@ -192,11 +231,10 @@ class Persons(list):
             raise PLCInvalidArgument, "Wrong person filter %r"%person_filter
 
         for person in persons:
-            person = Person(self.api, object = person)
-            person.tenant=None
-            if person.tenantId:
-                person.tenant = self.api.client_shell.keystone.tenants.find(id=person.tenantId)
+            keystone_user = self.api.client_shell.keystone.persons.find(id=person['keystone_id'])
+            tenant = self.api.client_shell.keystone.tenants.find(id=keystone_user.tenantId)
             if not columns or 'roles' in columns:
+                roles = self.api.client_shell.keystone.roles.roles_for_user(keystone_user, tenant)
                 person['roles'] = person.get_roles()
             if not columns or 'tenant_ids' in columns:
                 person['tenant_ids'] = person.get_tenants_ids()