04afe21d12c9c2d533c1e7dbf52baca00e13c1d5
[plcapi.git] / PLC / Methods / GetSliceKeys.py
1 # $Id$
2 from PLC.Method import Method
3 from PLC.Parameter import Parameter, Mixed
4 from PLC.Filter import Filter
5 from PLC.Auth import Auth
6 from PLC.Persons import Person, Persons
7 from PLC.Sites import Site, Sites
8 from PLC.Slices import Slice, Slices
9 from PLC.Keys import Key, Keys
10
11 class GetSliceKeys(Method):
12     """
13     Returns an array of structs containing public key info for users in 
14     the specified slices. If slice_filter is specified and is an array 
15     of slice identifiers or slice names, or a struct of slice 
16     attributes, only slices matching the filter will be returned. If 
17     return_fields is specified, only the specified details will be 
18     returned.
19
20     Users may only query slices of which they are members. PIs may
21     query any of the slices at their sites. Admins and nodes may query
22     any slice. If a slice that cannot be queried is specified in
23     slice_filter, details about that slice will not be returned.
24     """
25
26     roles = ['admin', 'pi', 'user', 'node']
27
28     accepts = [
29         Auth(),
30         Mixed([Mixed(Slice.fields['slice_id'],
31                      Slice.fields['name'])],
32               Filter(Slice.fields)),
33         Parameter([str], "List of fields to return", nullok = True)
34         ]
35
36     returns = [
37         {
38         'slice_id': Slice.fields['slice_id'],
39         'name': Slice.fields['name'], 
40         'person_id': Person.fields['person_id'], 
41         'email': Person.fields['email'],
42         'key': Key.fields['key']
43         }]
44
45     def call(self, auth, slice_filter = None, return_fields = None):
46         slice_fields = ['slice_id', 'name']
47         person_fields = ['person_id', 'email']
48         key_fields = ['key']
49
50         # If we are not admin, make sure to return only viewable
51         # slices.
52         if isinstance(self.caller, Person) and \
53            'admin' not in self.caller['roles']:
54             # Get slices that we are able to view
55             valid_slice_ids = self.caller['slice_ids']
56             if 'pi' in self.caller['roles'] and self.caller['site_ids']:
57                 sites = Sites(self.api, self.caller['site_ids'])
58                 for site in sites:
59                     valid_slice_ids += site['slice_ids']
60
61             if not valid_slice_ids:
62                 return []
63
64             if slice_filter is None:
65                 slice_filter = valid_slice_ids
66
67         if return_fields:
68             slice_return_fields = filter(lambda field: field in slice_fields, return_fields)
69             person_return_fields = filter(lambda field: field in person_fields, return_fields)
70             key_return_fields = filter(lambda field: field in key_fields, return_fields)
71         else:
72             slice_return_fields = slice_fields
73             person_return_fields = person_fields
74             key_return_fields = key_fields
75
76         # Must query at least Slice.slice_id, Slice.person_ids, 
77         # and Person.person_id and Person.key_ids so we can join data correctly
78         slice_added_fields = set(['slice_id', 'person_ids']).difference(slice_return_fields)
79         slice_return_fields += slice_added_fields
80         person_added_fields = set(['person_id', 'key_ids']).difference(person_return_fields)
81         person_return_fields += person_added_fields
82         key_added_fields = set(['key_id']).difference(key_return_fields)
83         key_return_fields += key_added_fields
84
85         # Get the slices
86         all_slices = Slices(self.api, slice_filter, slice_return_fields).dict('slice_id')
87         slice_ids = all_slices.keys()
88         slices = all_slices.values()
89
90         # Filter out slices that are not viewable
91         if isinstance(self.caller, Person) and \
92            'admin' not in self.caller['roles']:
93             slices = filter(lambda slice: slice['slice_id'] in valid_slice_ids, slices)
94         
95         # Get the persons
96         person_ids = set()
97         for slice in slices:
98             person_ids.update(slice['person_ids'])
99
100         all_persons = Persons(self.api, list(person_ids), person_return_fields).dict('person_id')
101         person_ids = all_persons.keys()
102         persons = all_persons.values()
103         
104         # Get the keys
105         key_ids = set()
106         for person in persons:
107             key_ids.update(person['key_ids'])
108         
109         all_keys = Keys(self.api, list(key_ids), key_return_fields).dict('key_id')
110         key_ids = all_keys.keys()
111         keys = all_keys.values()
112
113         # Create slice_keys list
114         slice_keys = []
115         slice_fields = list(set(slice_return_fields).difference(slice_added_fields))
116         person_fields = list(set(person_return_fields).difference(person_added_fields))
117         key_fields = list(set(key_return_fields).difference(key_added_fields))
118
119         for slice in slices:
120             slice_key = dict.fromkeys(slice_fields + person_fields + key_fields)
121             if not slice['person_ids']:
122                 continue
123             for person_id in slice['person_ids']:
124                 person = all_persons[person_id]
125                 if not person['key_ids']:
126                     continue
127                 for key_id in person['key_ids']:
128                     key = all_keys[key_id]
129                     slice_key.update(dict(filter(lambda (k, v): k in slice_fields, slice.items())))
130                     slice_key.update(dict(filter(lambda (k, v): k in person_fields, person.items())))
131                     slice_key.update(dict(filter(lambda (k, v): k in key_fields, key.items())))
132                     slice_keys.append(slice_key.copy())
133
134         return slice_keys       
135