remove PLC.Debug.log, use PLC.Logger.logger instead
[plcapi.git] / PLC / Methods / GetPersons.py
1 from PLC.Faults import *
2 from PLC.Method import Method
3 from PLC.Parameter import Parameter, Mixed
4 from PLC.Filter import Filter
5 from PLC.Persons import Person, Persons
6 from PLC.Sites import Site, Sites
7 from PLC.Auth import Auth
8 from PLC.Logger import logger
9
10 hidden_fields = ['password', 'verification_key', 'verification_expires']
11
12 class GetPersons(Method):
13     """
14     Returns an array of structs containing details about users. If
15     person_filter is specified and is an array of user identifiers or
16     usernames, or a struct of user attributes, only users matching the
17     filter will be returned. If return_fields is specified, only the
18     specified details will be returned.
19
20     Users and techs may only retrieve details about themselves. PIs
21     may retrieve details about themselves and others at their
22     sites. Admins and nodes may retrieve details about all accounts.
23     """
24
25     roles = ['admin', 'pi', 'user', 'tech', 'node']
26
27     accepts = [
28         Auth(),
29         Mixed([Mixed(Person.fields['person_id'],
30                      Person.fields['email'])],
31               Parameter(str,"email"),
32               Parameter(int,"person_id"),
33               Filter(Person.fields)),
34         Parameter([str], "List of fields to return", nullok = True)
35         ]
36
37     # Filter out password field
38     return_fields = dict(filter(lambda (field, value): field not in hidden_fields,
39                                 Person.fields.items()))
40     returns = [return_fields]
41
42     def call(self, auth, person_filter = None, return_fields = None):
43
44         logger.info("incoming GetPersons, filter={}, return fields={}"
45                     .format(person_filter, return_fields))
46
47         # If we are not admin, make sure to only return viewable accounts
48         if isinstance(self.caller, Person) and \
49            'admin' not in self.caller['roles']:
50             # Get accounts that we are able to view
51             valid_person_ids = [self.caller['person_id']]
52             if ('pi' in self.caller['roles'] or 'tech' in self.caller['roles']) \
53                and self.caller['site_ids']:
54                 sites = Sites(self.api, self.caller['site_ids'])
55                 for site in sites:
56                     valid_person_ids += site['person_ids']
57             if not valid_person_ids:
58                 return []
59
60             # this may look suspicious; what if person_filter is not None ?
61             # turns out the results are getting filtered again below, so we're safe
62             # although this part of the code does not always trigger, it's probably 
63             # a sensible performance enhancement for all the times 
64             # when GetPersons() gets called without an argument
65             if person_filter is None:
66                 person_filter = valid_person_ids
67
68         # Filter out password field
69         if return_fields:
70             return_fields = filter(lambda field: field not in hidden_fields,
71                                    return_fields)
72         else:
73             return_fields = self.return_fields.keys()
74
75         # Must query at least person_id, site_ids, and role_ids (see
76         # Person.can_view() and below).
77         if return_fields is not None:
78             added_fields = set(['person_id', 'site_ids', 'role_ids','roles']).difference(return_fields)
79             return_fields += added_fields
80         else:
81             added_fields = []
82
83         persons = Persons(self.api, person_filter, return_fields)
84
85         # Filter out accounts that are not viewable
86         if isinstance(self.caller, Person) and \
87            'admin' not in self.caller['roles']:
88             persons = filter(self.caller.can_view, persons)
89
90         # Remove added fields if not specified
91         if added_fields:
92             for person in persons:
93                 for field in added_fields:
94                     if field in person:
95                         del person[field]
96
97         return persons