implement GetPersons()
[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         'last_updated': Parameter(int, "Date and time of last update", ro = True),
38         'date_created': Parameter(int, "Date and time when account was created", ro = True),
39         'roles': Parameter([str], "List of roles"),
40         'site_ids': Parameter([int], "List of site identifiers"),
41         'key_ids': Parameter([int], "List of key identifiers"),
42         'slice_ids': 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['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['site_ids']).intersection(person['site_ids']):
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.tenants.create(**self)
119  
120
121 class Persons(NovaTable):
122     """
123     Representation of row(s) from the persons table in the
124     database.
125     """
126
127     def __init__(self, api, person_filter = None, columns = None):
128         self.api = api
129         if not person_filter:
130             persons = self.api.client_shell.keystone.users.findall()
131         elif isinstance(person_filter, (list, tuple, set)):
132             # Separate the list into integers and strings
133             persons = self.api.client_shell.keystone.users.findall()
134             persons = [person for person in persons if person.id in site_filter]
135         elif isinstance(person_filter, dict):
136             persons = [self.api.client_shell.keystone.users.findall(**site_filter)]
137         elif isinstance (person_filter, StringTypes):
138             persons = [self.api.client_shell.keystone.users.find(**site_filter)]
139         else:
140             raise PLCInvalidArgument, "Wrong person filter %r"%person_filter
141
142         for person in persons:
143             person = Person(self.api, object = person)
144             self.append(person)