updated fields
[plcapi.git] / PLC / Persons.py
1 #
2 # Functions for interacting with the persons table in the database
3 #
4
5 from types import StringTypes
6 try:
7     from hashlib import md5
8 except ImportError:
9     from md5 import md5
10 import time
11 from random import Random
12 import re
13 import crypt
14
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
23
24 class Person(NovaObject):
25     """
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().
29     """
30
31     fields = {
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),
43         }
44
45     def validate_email(self, email):
46         """
47         Validate email address. Stolen from Mailman.
48         """
49         email = email.lower()
50         invalid_email = PLCInvalidArgument("Invalid e-mail address")
51
52         if not email:
53             raise invalid_email
54
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):
57             raise invalid_email
58
59         return email
60
61     def can_update(self, person):
62         """
63         Returns true if we can update the specified person. We can
64         update a person if:
65
66         1. We are the person.
67         2. We are an admin.
68         3. We are a PI and the person is a user or tech or at
69            one of our sites.
70         """
71
72         assert isinstance(person, Person)
73
74         if self.person_id == person.person_id:
75             return True
76
77         if 'admin' in self['roles']:
78             return True
79
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']))
84
85         return False
86
87     def can_view(self, person):
88         """
89         Returns true if we can view the specified person. We can
90         view a person if:
91
92         1. We are the person.
93         2. We are an admin.
94         3. We are a PI or Tech and the person is at one of our sites.
95         """
96
97         assert isinstance(person, Person)
98
99         if self.can_update(person):
100             return True
101
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']):
105                 return True
106
107         return False
108
109     #add_role = Row.add_object(Role, 'person_role')
110     #remove_role = Row.remove_object(Role, 'person_role')
111
112     #add_key = Row.add_object(Key, 'person_key')
113     #remove_key = Row.remove_object(Key, 'person_key')
114
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)
119
120     def delete(self):
121         # delete relationships
122         SlicePerson().delete.filter({'person_id': self['person_id']})
123
124         # delete nova object
125         user = self.api.client_shell.keystone.users.find(**self)
126         self.api.client_shell.keystone.users.delete(user)
127
128  
129     def get_roles(self):
130         roles = []
131         if self.tenant:
132             roles = self.api.client_shell.keystone.roles.roles_for_user(self.object, self.tenant)
133         return [role.name for role in roles] 
134
135     def get_tenants_ids(self):
136         tenants = []
137         if self.tenantId:
138             tenants = [self.tenantId]
139         return tenants
140
141     def get_key_ids(self):
142         return []
143
144 class Persons(NovaTable):
145     """
146     Representation of row(s) from the persons table in the
147     database.
148     """
149
150     def __init__(self, api, person_filter = None, columns = None):
151         self.api = api
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)]
162         else:
163             raise PLCInvalidArgument, "Wrong person filter %r"%person_filter
164
165         for person in persons:
166             person = Person(self.api, object = person)
167             person.tenant=None
168             if person.tenantId:
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]
179             self.append(person)