registrationview
[myslice.git] / portal / views.py
1 # -*- coding: utf-8 -*-
2 #
3 # portal/views.py: views for the portal application
4 # This file is part of the Manifold project.
5 #
6 # Authors:
7 #   Jordan AugĂ© <jordan.auge@lip6.fr>
8 #   Mohammed Yasin Rahman <mohammed-yasin.rahman@lip6.fr>
9 # Copyright 2013, UPMC Sorbonne UniversitĂ©s / LIP6
10 #
11 # This program is free software; you can redistribute it and/or modify it under
12 # the terms of the GNU General Public License as published by the Free Software
13 # Foundation; either version 3, or (at your option) any later version.
14
15 # This program is distributed in the hope that it will be useful, but WITHOUT
16 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18 # details.
19
20 # You should have received a copy of the GNU General Public License along with
21 # this program; see the file COPYING.  If not, write to the Free Software
22 # Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 import json
25
26 from django.http                 import HttpResponseRedirect, HttpResponse
27 from django.views.generic.base   import TemplateView
28 from django.shortcuts            import render
29 from django.template.loader      import render_to_string
30 from django.core.mail            import send_mail
31 from django.utils.decorators     import method_decorator
32 from django.contrib.auth.decorators import login_required
33
34 from myslice.viewutils           import topmenu_items, the_user
35
36 from plugins.lists.simplelist    import SimpleList
37 from plugins.hazelnut            import Hazelnut
38 from plugins.pres_view           import PresView
39 from portal.event import Event
40
41 from portal                      import signals
42 from portal.forms                import SliceRequestForm
43 from portal.util                 import RegistrationView, ActivationView
44 from portal.models               import PendingUser, PendingSlice
45 from portal.actions              import authority_get_pi_emails, get_request_by_authority, manifold_add_user, manifold_update_user
46 from manifold.manifoldapi        import execute_query
47 from manifold.core.query         import Query
48 from unfold.page                 import Page
49
50 # NOTE
51 # initially all the portal views were defined in this single file
52 # all the other ones have now migrated into separate classes/files for more convenience
53 # I'm leaving these ones here for now as I could not exactly figure what the purpose was 
54 # (i.e. what the correct name should be, as presviewview was a bit cryptic)
55 class PresViewView(TemplateView):
56     template_name = "view-unfold1.html"
57
58     def get_context_data(self, **kwargs):
59
60         page = Page(self.request)
61
62         pres_view = PresView(page = page)
63
64         context = super(PresViewView, self).get_context_data(**kwargs)
65
66         #context['ALL_STATIC'] = "all_static"
67         context['unfold1_main'] = pres_view.render(self.request)
68
69         # XXX This is repeated in all pages
70         # more general variables expected in the template
71         context['title'] = 'Test view that combines various plugins'
72         # the menu items on the top
73         context['topmenu_items'] = topmenu_items('PresView', self.request)
74         # so we can sho who is logged
75         context['username'] = the_user(self.request)
76
77         prelude_env = page.prelude_env()
78         context.update(prelude_env)
79
80         return context
81
82 def json_me(config_file,type):
83     json_answer = ''
84     for ligne in config_file:
85         if not ligne.startswith('#'):
86             args = ligne.split(';')
87             json_answer += str('{ "name": "' + args[0] + '" ,"id":"' + args[1]  + '" ,"descriptif":"' + args[2]+'"')
88             if type!="dynamic":
89                 json_answer += str(',"contraints":')
90                 if args[3]=="":
91                     json_answer += str('""')
92                 else:
93                     json_answer += str(args[3])
94             json_answer += str('},')
95     return json_answer[:-1]
96
97
98 DIR = '/var/myslice/'
99 STATIC = '%s/config_method_static' % DIR
100 DYNAMIC = '%s/config_method_dynamic' % DIR
101 ANIMATION = '%s/config_method_animation' % DIR
102
103 def pres_view_methods(request, type):
104
105     if type ==None:
106         return 0
107     elif type =="static":
108         config = open(STATIC, "r")
109         json_answer = str('{ "options": [')
110         json_answer += str(json_me(config,"static"))
111         json_answer += str('] }')
112         config.close()
113     elif type =="dynamic":
114         config = open(DYNAMIC, "r")
115         json_answer = str('{ "options": [')
116         json_answer += str(json_me(config,"dynamic"))
117         json_answer += str('] }')
118         config.close()
119     elif type =="animation":
120         config = open(ANIMATION, "r")
121         json_answer = str('{ "options": [')
122         json_answer += str(json_me(config,"animation"))
123         json_answer += str('] }')
124         config.close()
125     elif type =="all":
126         config = open(STATIC, "r")
127         json_answer = str('{ "static": [')
128         json_answer += str(json_me(config,"static"))
129         json_answer += str('],')
130         json_answer += str('"dynamic": [')
131         config.close()
132         config = open(DYNAMIC, "r")
133         json_answer += str(json_me(config,"dynamic"))
134         json_answer += str('],')
135         json_answer += str('"animation": [')
136         config.close()
137         config = open(ANIMATION, "r")
138         json_answer += str(json_me(config,"animation"))
139         json_answer += str('] }')
140         config.close()
141     else:
142         return 0
143     return HttpResponse (json_answer, mimetype="application/json")
144
145 def pres_view_animation(request, constraints, id):
146
147 # sites crees depuis 2008
148 # static.py?contraints=']date_created':1262325600&id='name_id"'
149
150     # method = request.getvalue('method') #ex : GetSites
151     #constraints = "']date_created':1262325600"
152     #id = "2"
153
154     if id == None:
155         return 0
156
157     # method = 'GetSites'#request.getvalue('method') #ex : GetSites
158     # constraints = {}#request.getvalue('constraints') // nul = {}
159     # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
160
161     config_file = open(ANIMATION, "r")
162     for ligne in config_file:
163         if not ligne.startswith('#'):
164             ligne = ligne.split('\n')
165             first = ligne[0].split(';')
166             if (str(first[1]) == str(id)):
167                 save = first
168     config_file.close()
169
170     #Les print_method, print_option sont definis par le client (js)
171     #Les animations acceptent que les connexions anonymous
172     # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
173     args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
174
175
176     #Creation d'un objet event
177     event = Event(args)
178     cmd = [{"params": {
179             "data": {
180                 "print_options": event.print_options,
181                 "print_method": event.print_method,
182                 "message": event.data
183             }
184         }
185     }]
186
187     json_answer = json.dumps(cmd)
188     return HttpResponse (json_answer, mimetype="application/json")
189
190 def pres_view_static(request, constraints, id):
191     #constraints = "']date_created':1262325600"
192     #id = "2"
193
194     # method = 'GetSites'#request.getvalue('method') #ex : GetSites
195     # constraints = {}#request.getvalue('constraints') // nul = {}
196     # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
197
198     config_file = open(STATIC, "r")
199     for ligne in config_file:
200         if not ligne.startswith('#'):
201             ligne = ligne.split('\n')
202             first = ligne[0].split(';')
203             if (str(first[1]) == str(id)):
204                 save = first
205     config_file.close()
206
207     #Les print_method, print_option sont definis par le client (js)
208     #Les animations acceptent que les connexions anonymous
209     # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
210     args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
211
212
213     #Creation d'un objet event
214     event = Event(args)
215     cmd = [{"params": {
216             "data": {
217                 "print_options": event.print_options,
218                 "print_method": event.print_method,
219                 "message": event.data
220             }
221         }
222     }]
223
224     json_answer = json.dumps(cmd)
225     return HttpResponse (json_answer, mimetype="application/json")
226
227 class ValidatePendingView(TemplateView):
228     template_name = "validate_pending.html"
229
230     def get_context_data(self, **kwargs):
231         # We might have slices on different registries with different user accounts 
232         # We note that this portal could be specific to a given registry, to which we register users, but i'm not sure that simplifies things
233         # Different registries mean different identities, unless we identify via SFA HRN or have associated the user email to a single hrn
234
235         #messages.info(self.request, 'You have logged in')
236         page = Page(self.request)
237
238         ctx_my_authorities = {}
239         ctx_delegation_authorities = {}
240
241
242         # The user need to be logged in
243         if the_user(self.request):
244             # Who can a PI validate:
245             # His own authorities + those he has credentials for.
246             # In MySlice we need to look at credentials also.
247             
248
249             # XXX This will have to be asynchroneous. Need to implement barriers,
250             # for now it will be sufficient to have it working statically
251
252             # get user_id to later on query accounts
253             # XXX Having real query plan on local tables would simplify all this
254             # XXX $user_email is still not available for local tables
255             #user_query = Query().get('local:user').filter_by('email', '==', '$user_email').select('user_id')
256             user_query = Query().get('local:user').filter_by('email', '==', the_user(self.request)).select('user_id')
257             user, = execute_query(self.request, user_query)
258             user_id = user['user_id']
259
260             # Query manifold to learn about available SFA platforms for more information
261             # In general we will at least have the portal
262             # For now we are considering all registries
263             all_authorities = []
264             platform_ids = []
265             sfa_platforms_query = Query().get('local:platform').filter_by('gateway_type', '==', 'sfa').select('platform_id', 'platform', 'auth_type')
266             sfa_platforms = execute_query(self.request, sfa_platforms_query)
267             for sfa_platform in sfa_platforms:
268                 print "SFA PLATFORM > ", sfa_platform['platform']
269                 if not 'auth_type' in sfa_platform:
270                     continue
271                 auth = sfa_platform['auth_type']
272                 if not auth in all_authorities:
273                     all_authorities.append(auth)
274                 platform_ids.append(sfa_platform['platform_id'])
275
276             # We can check on which the user has authoritity credentials = PI rights
277             credential_authorities = set()
278             credential_authorities_expired = set()
279
280             # User account on these registries
281             user_accounts_query = Query.get('local:account').filter_by('user_id', '==', user_id).filter_by('platform_id', 'included', platform_ids).select('config')
282             user_accounts = execute_query(self.request, user_accounts_query)
283             #print "=" * 80
284             #print user_accounts
285             #print "=" * 80
286             for user_account in user_accounts:
287                 config = json.loads(user_account['config'])
288                 creds = []
289                 if 'authority_credentials' in config:
290                     for authority_hrn, credential in config['authority_credentials'].items():
291                         #if credential is not expired:
292                         credential_authorities.add(authority_hrn)
293                         #else
294                         #    credential_authorities_expired.add(authority_hrn)
295                 if 'delegated_authority_credentials' in config:
296                     for authority_hrn, credential in config['delegated_authority_credentials'].items():
297                         #if credential is not expired:
298                         credential_authorities.add(authority_hrn)
299                         #else
300                         #    credential_authorities_expired.add(authority_hrn)
301
302             print 'credential_authorities =', credential_authorities
303             print 'credential_authorities_expired =', credential_authorities_expired
304
305             # ** Where am I a PI **
306             # For this we need to ask SFA (of all authorities) = PI function
307             pi_authorities_query = Query.get('user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
308             pi_authorities_tmp = execute_query(self.request, pi_authorities_query)
309             pi_authorities = set()
310             for pa in pi_authorities_tmp:
311                 pi_authorities |= set(pa['pi_authorities'])
312
313             print "pi_authorities =", pi_authorities
314             
315             # My authorities + I have a credential
316             pi_credential_authorities = pi_authorities & credential_authorities
317             pi_no_credential_authorities = pi_authorities - credential_authorities - credential_authorities_expired
318             pi_expired_credential_authorities = pi_authorities & credential_authorities_expired
319             # Authorities I've been delegated PI rights
320             pi_delegation_credential_authorities = credential_authorities - pi_authorities
321             pi_delegation_expired_authorities = credential_authorities_expired - pi_authorities
322
323             print "pi_credential_authorities =", pi_credential_authorities
324             print "pi_no_credential_authorities =", pi_no_credential_authorities
325             print "pi_expired_credential_authorities =", pi_expired_credential_authorities
326             print "pi_delegation_credential_authorities = ", pi_delegation_credential_authorities
327             print "pi_delegation_expired_authorities = ", pi_delegation_expired_authorities
328
329             # Summary intermediary
330             pi_my_authorities = pi_credential_authorities | pi_no_credential_authorities | pi_expired_credential_authorities
331             pi_delegation_authorities = pi_delegation_credential_authorities | pi_delegation_expired_authorities
332
333             print "--"
334             print "pi_my_authorities = ", pi_my_authorities
335             print "pi_delegation_authorities = ", pi_delegation_authorities
336
337             # Summary all
338             queried_pending_authorities = pi_my_authorities | pi_delegation_authorities
339             print "----"
340             print "queried_pending_authorities = ", queried_pending_authorities
341
342             requests = get_request_by_authority(queried_pending_authorities)
343             for request in requests:
344                 auth_hrn = request['authority_hrn']
345
346                 if auth_hrn in pi_my_authorities:
347                     dest = ctx_my_authorities
348
349                     # define the css class
350                     if auth_hrn in pi_credential_authorities:
351                         request['allowed'] = 'allowed'
352                     elif auth_hrn in pi_expired_credential_authorities:
353                         request['allowed'] = 'expired'
354                     else: # pi_no_credential_authorities
355                         request['allowed'] = 'denied'
356
357                 elif auth_hrn in pi_delegation_authorities:
358                     dest = ctx_delegation_authorities
359
360                     if auth_hrn in pi_delegation_credential_authorities:
361                         request['allowed'] = 'allowed'
362                     else: # pi_delegation_expired_authorities
363                         request['allowed'] = 'expired'
364
365                 else:
366                     continue
367
368                 if not auth_hrn in dest:
369                     dest[auth_hrn] = []
370                 dest[auth_hrn].append(request) 
371         
372         context = super(ValidatePendingView, self).get_context_data(**kwargs)
373         context['my_authorities']   = ctx_my_authorities
374         context['delegation_authorities'] = ctx_delegation_authorities
375
376         # XXX This is repeated in all pages
377         # more general variables expected in the template
378         context['title'] = 'Test view that combines various plugins'
379         # the menu items on the top
380         context['topmenu_items'] = topmenu_items('Dashboard', self.request) 
381         # so we can sho who is logged
382         context['username'] = the_user(self.request) 
383
384         # XXX We need to prepare the page for queries
385         #context.update(page.prelude_env())
386
387         return context