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