2 # Functions for interacting with the persons table in the database
5 from types import StringTypes
7 from hashlib import md5
11 from random import Random
15 from PLC.Faults import *
16 from PLC.Debug import log
17 from PLC.Parameter import Parameter, Mixed
18 from PLC.Table import Row, Table
19 from PLC.Roles import Role, Roles
20 from PLC.Keys import Key, Keys
21 from PLC.Messages import Message, Messages
22 from PLC.NovaTable import NovaObject, NovaTable
24 class Person(NovaObject):
26 Representation of a row in the persons table. To use, optionally
27 instantiate with a dict of values. Update as you would a
28 dict. Commit to the database with sync().
32 'person_id': Parameter(str, "User identifier"),
33 'name': Parameter(str, "Given name", max = 128),
34 'email': Parameter(str, "Primary e-mail address", max = 254),
35 'enabled': Parameter(bool, "Has been enabled"),
36 'password': Parameter(str, "Account password in crypt() form", max = 254),
37 'tenant_ids': Parameter(str, "Site identifier"),
38 #'last_updated': Parameter(int, "Date and time of last update"),
39 #'date_created': Parameter(int, "Date and time when account was created"),
40 'roles': Parameter([str], "List of roles", joined=True),
41 'key_ids': Parameter([str], "List of key identifiers", joined=True),
42 'slice_ids': Parameter([int], "List of slice identifiers", joined=True),
45 def validate_email(self, email):
47 Validate email address. Stolen from Mailman.
50 invalid_email = PLCInvalidArgument("Invalid e-mail address")
55 email_re = re.compile('\A[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9._\-]+\.[a-zA-Z]+\Z')
56 if not email_re.match(email):
61 def can_update(self, person):
63 Returns true if we can update the specified person. We can
68 3. We are a PI and the person is a user or tech or at
72 assert isinstance(person, Person)
74 if self.person_id == person.person_id:
77 if 'admin' in self['roles']:
80 if 'pi' in self['roles']:
81 if set(self['tenants']).intersection(person['tenants']):
82 # non-admin users cannot update a person who is neither a PI or ADMIN
83 return (not set(['pi','admin']).intersection(person['roles']))
87 def can_view(self, person):
89 Returns true if we can view the specified person. We can
94 3. We are a PI or Tech and the person is at one of our sites.
97 assert isinstance(person, Person)
99 if self.can_update(person):
102 # pis and techs can see all people on their site
103 if set(['pi','tech']).intersection(self['roles']):
104 if set(self['site_ids']).intersection(person['site_ids']):
109 #add_role = Row.add_object(Role, 'person_role')
110 #remove_role = Row.remove_object(Role, 'person_role')
112 #add_key = Row.add_object(Key, 'person_key')
113 #remove_key = Row.remove_object(Key, 'person_key')
115 def sync(self, insert=False, validate=True):
116 NovaObject.sync(self, insert, validate)
117 if insert == True or 'person_id' not in self:
118 self.object = self.api.client_shell.keystone.users.create(**self)
121 # delete relationships
122 SlicePerson().delete.filter({'person_id': self['person_id']})
125 user = self.api.client_shell.keystone.users.find(**self)
126 self.api.client_shell.keystone.users.delete(user)
132 roles = self.api.client_shell.keystone.roles.roles_for_user(self.object, self.tenant)
133 return [role.name for role in roles]
135 def get_tenants_ids(self):
138 tenants = [self.tenantId]
141 def get_key_ids(self):
144 class Persons(NovaTable):
146 Representation of row(s) from the persons table in the
150 def __init__(self, api, person_filter = None, columns = None):
152 if not person_filter:
153 persons = self.api.client_shell.keystone.users.findall()
154 elif isinstance(person_filter, (list, tuple, set)):
155 # Separate the list into integers and strings
156 persons = self.api.client_shell.keystone.users.findall()
157 persons = [person for person in persons if person.id in person_filter]
158 elif isinstance(person_filter, dict):
159 persons = self.api.client_shell.keystone.users.findall(**person_filter)
160 elif isinstance (person_filter, StringTypes):
161 persons = [self.api.client_shell.keystone.users.find(id=person_filter)]
163 raise PLCInvalidArgument, "Wrong person filter %r"%person_filter
165 for person in persons:
166 person = Person(self.api, object = person)
169 person.tenant = self.api.client_shell.keystone.tenants.find(id=person.tenantId)
170 if not columns or 'roles' in columns:
171 person['roles'] = person.get_roles()
172 if not columns or 'tenant_ids' in columns:
173 person['tenant_ids'] = person.get_tenants_ids()
174 if not columns or 'key_ids' in columns:
175 person['key_ids'] = person.get_keys_ids()
176 if not columns or 'slice_ids' in columns:
177 person_slices = SlicePerson().select(filter={'person_id': person.person_id})
178 person['slice_ids'] = [rec.slice_id for rec in person_slices]