implement AddPerson, DeletePerson
[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         '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_id': Parameter(str, "Tenant identifier"),
38         'last_updated': Parameter(int, "Date and time of last update", ro = True),
39         'date_created': Parameter(int, "Date and time when account was created", ro = True),
40         'roles': Parameter([str], "List of roles"),
41         'keys': Parameter([int], "List of key identifiers"),
42         'slices': Parameter([int], "List of slice identifiers"),
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.id == 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 id not in self:
118             self.object = self.api.client_shell.keystone.users.create(**self)
119  
120     def get_roles(self):
121         roles = []
122         if self.tenant:
123             roles = self.api.client_shell.keystone.roles.roles_for_user(self.object, self.tenant)
124         return [role.name for role in roles] 
125
126     def get_tenants(self):
127         tenants = []
128         if self.tenantId:
129             tenants = [self.tenantId]
130         return tenants
131
132 class Persons(NovaTable):
133     """
134     Representation of row(s) from the persons table in the
135     database.
136     """
137
138     def __init__(self, api, person_filter = None, columns = None):
139         self.api = api
140         if not person_filter:
141             persons = self.api.client_shell.keystone.users.findall()
142         elif isinstance(person_filter, (list, tuple, set)):
143             # Separate the list into integers and strings
144             persons = self.api.client_shell.keystone.users.findall()
145             persons = [person for person in persons if person.id in person_filter]
146         elif isinstance(person_filter, dict):
147             persons = self.api.client_shell.keystone.users.findall(**person_filter)
148         elif isinstance (person_filter, StringTypes):
149             persons = [self.api.client_shell.keystone.users.find(id=person_filter)]
150         else:
151             raise PLCInvalidArgument, "Wrong person filter %r"%person_filter
152
153         for person in persons:
154             person = Person(self.api, object = person)
155             person.tenant=None
156             if person.tenantId:
157                 person.tenant = self.api.client_shell.keystone.tenants.find(id=person.tenantId)
158             person['roles'] = person.get_roles()
159             person['tenants'] = person.get_tenants() 
160             self.append(person)