Fix: merge conflict def def account_process(): in views.py
[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 from django.conf                 import settings
25 from django.contrib.sites.models import Site, RequestSite
26 from django.contrib              import messages
27 from django.views.generic        import View
28 from django.views.generic.base   import TemplateView
29 from django.shortcuts            import render
30 from django.template.loader      import render_to_string
31 from django.core.mail            import send_mail
32 from django.utils.decorators     import method_decorator
33 from django.contrib.auth.decorators import login_required
34
35 from plugins.lists.simplelist    import SimpleList
36 from plugins.hazelnut            import Hazelnut
37 from plugins.pres_view           import PresView
38 from portal.event import Event
39 import json
40
41 from portal                      import signals
42 from portal.forms                import SliceRequestForm, ContactForm
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 from myslice.viewutils           import topmenu_items, the_user
50 from django.http                 import HttpResponseRedirect, HttpResponse
51
52 from M2Crypto                    import Rand, RSA, BIO
53 import os, re
54
55 # View for 1 platform and its details
56 class PlatformView(TemplateView):
57     template_name = "platform.html"
58
59     def get_context_data(self, **kwargs):
60         page = Page(self.request)
61
62         for key, value in kwargs.iteritems():
63             print "%s = %s" % (key, value)       
64             if key == "platformname":
65                 platformname=value
66                 
67         network_query  = Query().get('local:platform').filter_by('platform', '==', platformname).select('platform','platform_longname','gateway_type')
68         page.enqueue_query(network_query)
69
70         page.expose_js_metadata()
71         page.expose_queries()
72         networklist = Hazelnut(
73             page  = page,
74             title = 'List',
75             domid = 'checkboxes',
76             # this is the query at the core of the slice list
77             query = network_query,
78             query_all = network_query,
79             checkboxes = False,
80             datatables_options = {
81             # for now we turn off sorting on the checkboxes columns this way
82             # this of course should be automatic in hazelnut
83             'aoColumns'      : [None, None, None, None, {'bSortable': False}],
84             'iDisplayLength' : 25,
85             'bLengthChange'  : True,
86             },
87         )
88 #
89 #        networklist = SimpleList(
90 #            title = None,
91 #            page  = page,
92 #            key   = 'platform',
93 #            query = network_query,
94 #        )
95
96         context = super(PlatformView, self).get_context_data(**kwargs)
97         context['person']   = self.request.user
98         context['networks'] = networklist.render(self.request)
99
100         # XXX This is repeated in all pages
101         # more general variables expected in the template
102         context['title'] = 'Platforms connected to MySlice'
103         # the menu items on the top
104         context['topmenu_items'] = topmenu_items('Platforms', self.request)
105         # so we can sho who is logged
106         context['username'] = the_user(self.request)
107
108         context.update(page.prelude_env())
109
110         return context
111
112
113
114 #class for my_account
115 class AccountView(TemplateView):
116     template_name = "my_account.html"
117     
118     #This view requires login 
119     @method_decorator(login_required)
120     def dispatch(self, *args, **kwargs):
121         return super(AccountView, self).dispatch(*args, **kwargs)
122
123
124     def get_context_data(self, **kwargs):
125         #page = Page(self.request)
126
127         user_query  = Query().get('local:user').select('config','email')
128         user_details = execute_query(self.request, user_query)
129         
130         # not always found in user_details...
131         config={}
132         for user_detail in user_details:
133             #email = user_detail['email']
134             if user_detail['config']:
135                 config = json.loads(user_detail['config'])
136
137         platform_query  = Query().get('local:platform').select('platform_id','platform')
138         account_query  = Query().get('local:account').select('user_id','platform_id','auth_type','config')
139         platform_details = execute_query(self.request, platform_query)
140         account_details = execute_query(self.request, account_query)
141        
142         # initial assignment needed for users having no account  
143         platform_name = ''
144         account_type = ''
145         account_usr_hrn = ''
146         account_pub_key = ''
147         platform_name_list = []
148         account_type_list = []
149         usr_hrn_list = []
150         pub_key_list = []          
151         for account_detail in account_details:
152             for platform_detail in platform_details:
153                 if platform_detail['platform_id'] == account_detail['platform_id']:
154                     platform_name = platform_detail['platform']
155                     account_type = account_detail['auth_type']
156                     account_config = json.loads(account_detail['config'])
157                     # a bit more pythonic
158                     account_usr_hrn = account_config.get('user_hrn','N/A')
159                     account_pub_key = account_config.get('user_public_key','N/A')
160                     
161                     platform_name_list.append(platform_name)
162                     account_type_list.append(account_type)
163                     usr_hrn_list.append(account_usr_hrn)
164                     pub_key_list.append(account_pub_key)
165         
166         # combining 4 lists into 1 [to render in the template] 
167         lst = [{'platform_name': t[0], 'account_type': t[1], 'usr_hrn':t[2], 'usr_pubkey':t[3]} for t in zip(platform_name_list, account_type_list, usr_hrn_list, pub_key_list)]    
168         #print "test"
169         #print lst
170
171         context = super(AccountView, self).get_context_data(**kwargs)
172         context['data'] = lst
173         context['person']   = self.request.user
174         context ['firstname'] = config.get('firstname',"?")
175         context ['lastname'] = config.get('lastname',"?")
176         context ['fullname'] = context['firstname'] +' '+ context['lastname']
177         context ['authority'] = config.get('authority',"Unknown Authority")
178         #context['users'] = userlist.render(self.request)
179         
180         # XXX This is repeated in all pages
181         # more general variables expected in the template
182         context['title'] = 'Platforms connected to MySlice'
183         # the menu items on the top
184         context['topmenu_items'] = topmenu_items('My Account', self.request)
185         # so we can sho who is logged
186         context['username'] = the_user(self.request)
187 #        context ['firstname'] = config['firstname']
188         #context.update(page.prelude_env())
189         return context
190
191 @login_required
192 #my_acc form value processing
193 def account_process(request):
194     user_query  = Query().get('local:user').select('password','config')
195     user_details = execute_query(request, user_query)
196
197     if 'submit_name' in request.POST:
198         edited_first_name =  request.POST['fname']
199         edited_last_name =  request.POST['lname']
200         
201         config={}
202         for user_config in user_details:
203         #email = user_detail['email']
204             if user_config['config']:
205                 config = json.loads(user_config['config'])
206                 config['firstname'] = edited_first_name
207                 config['lastname'] = edited_last_name
208                 config['authority'] = config.get('authority','Unknown Authority')
209                 updated_config = json.dumps(config)
210         
211         # updating config local:user in manifold       
212         user_params = { 'config': updated_config}
213         manifold_update_user(request,user_params)
214         # this will be depricated, we will show the success msg in same page
215         return HttpResponse('Sucess: First Name and Last Name Updated!')       
216     elif 'submit_pass' in request.POST:
217         edited_password = request.POST['password']
218         
219         for user_pass in user_details:
220             user_pass['password'] = edited_password
221         #updating password in local:user
222         user_params = { 'password': user_pass['password']}
223         manifold_update_user(request,user_params)
224
225         return HttpResponse('Success: Password Changed!!')
226     elif 'generate' in request.POST:
227         # Generate public and private keys using SFA Library
228         from sfa.trust.certificate  import Keypair
229         k = Keypair(create=True)
230         public_key = k.get_pubkey_string()
231         private_key = k.as_pem()
232         private_key = ''.join(private_key.split())
233         public_key = "ssh-rsa " + public_key
234         # Saving to DB
235         keypair = '{"user_public_key":"'+ public_key + '", "user_private_key":"'+ private_key + '"}'
236 #        keypair = re.sub("\r", "", keypair)
237 #        keypair = re.sub("\n", "\\n", keypair)
238 #        #keypair = keypair.rstrip('\r\n')
239 #        keypair = ''.join(keypair.split())
240         get_user.keypair = keypair
241         get_user.save()
242         return HttpResponse('Success: New Keypair Generated! %s' % keypair)
243
244     elif 'upload_key' in request.POST:
245         up_file = request.FILES['pubkey']
246         file_content =  up_file.read()
247         file_name = up_file.name
248         file_extension = os.path.splitext(file_name)[1] 
249         allowed_extension =  ['.pub','.txt']
250         if file_extension in allowed_extension and re.search(r'ssh-rsa',file_content):
251             file_content = '{"user_public_key":"'+ file_content +'"}'
252             file_content = re.sub("\r", "", file_content)
253             file_content = re.sub("\n", "\\n",file_content)
254             file_content = ''.join(file_content.split())
255             get_user.keypair = file_content
256             get_user.save()
257             return HttpResponse('Success: Publickey uploaded! Old records overwritten')
258         else:
259             return HttpResponse('Please upload a valid RSA public key [.txt or .pub].')    
260         
261     else:
262         message = 'You submitted an empty form.'
263         return HttpResponse(message)
264
265 def register_4m_f4f(request):
266     errors = []
267
268     authorities_query = Query.get('authority').filter_by('authority_hrn', 'included', ['ple.inria', 'ple.upmc']).select('name', 'authority_hrn')
269     #authorities_query = Query.get('authority').select('authority_hrn')
270     authorities = execute_query(request, authorities_query)
271
272     if request.method == 'POST':
273         # We shall use a form here
274
275         #get_email = PendingUser.objects.get(email)
276         reg_fname = request.POST.get('firstname', '')
277         reg_lname = request.POST.get('lastname', '')
278         reg_aff = request.POST.get('affiliation','')
279         reg_auth = request.POST.get('authority_hrn', '')
280         reg_email = request.POST.get('email','').lower()
281         
282         #POST value validation  
283         if (re.search(r'^[\w+\s.@+-]+$', reg_fname)==None):
284             errors.append('First Name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
285             #return HttpResponse("Only Letters, Numbers, - and _ allowd in First Name")
286             #return render(request, 'register_4m_f4f.html')
287         if (re.search(r'^[\w+\s.@+-]+$', reg_lname) == None):
288             errors.append('Last Name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
289             #return HttpResponse("Only Letters, Numbers, - and _ is allowed in Last name")
290             #return render(request, 'register_4m_f4f.html')
291         if (re.search(r'^[\w+\s.@+-]+$', reg_aff) == None):
292             errors.append('Affiliation may contain only letters, numbers, spaces and @/./+/-/_ characters.')
293             #return HttpResponse("Only Letters, Numbers and _ is allowed in Affiliation")
294             #return render(request, 'register_4m_f4f.html')
295         # XXX validate authority hrn !!
296         if PendingUser.objects.filter(email__iexact=reg_email):
297             errors.append('Email already registered.Please provide a new email address.')
298             #return HttpResponse("Email Already exists")
299             #return render(request, 'register_4m_f4f.html')
300         if 'generate' in request.POST['question']:
301             # Generate public and private keys using SFA Library
302             from sfa.trust.certificate  import Keypair
303             k = Keypair(create=True)
304             public_key = k.get_pubkey_string()
305             private_key = k.as_pem()
306             private_key = ''.join(private_key.split())
307             public_key = "ssh-rsa " + public_key
308             # Saving to DB
309             keypair = '{"user_public_key":"'+ public_key + '", "user_private_key":"'+ private_key + '"}'
310 #            keypair = re.sub("\r", "", keypair)
311 #            keypair = re.sub("\n", "\\n", keypair)
312 #            #keypair = keypair.rstrip('\r\n')
313 #            keypair = ''.join(keypair.split())
314         else:
315             up_file = request.FILES['user_public_key']
316             file_content =  up_file.read()
317             file_name = up_file.name
318             file_extension = os.path.splitext(file_name)[1]
319             allowed_extension =  ['.pub','.txt']
320             if file_extension in allowed_extension and re.search(r'ssh-rsa',file_content):
321                 keypair = '{"user_public_key":"'+ file_content +'"}'
322                 keypair = re.sub("\r", "", keypair)
323                 keypair = re.sub("\n", "\\n",keypair)
324                 keypair = ''.join(keypair.split())
325             else:
326                 errors.append('Please upload a valid RSA public key [.txt or .pub].')
327
328         #b = PendingUser(first_name=reg_fname, last_name=reg_lname, affiliation=reg_aff, 
329         #                email=reg_email, password=request.POST['password'], keypair=keypair)
330         #b.save()
331         if not errors:
332             b = PendingUser(
333                 first_name=reg_fname, 
334                 last_name=reg_lname, 
335                 affiliation=reg_aff,
336                 authority_hrn=reg_auth,
337                 email=reg_email, 
338                 password=request.POST['password'],
339                 keypair=keypair
340             )
341             b.save()
342
343             # Send email
344             ctx = {
345                 first_name   : reg_fname, 
346                 last_name    : reg_lname, 
347                 affiliation  : reg_aff,
348                 authority_hrn: reg_auth,
349                 email        : reg_email, 
350                 keypair      : keypair,
351                 cc_myself    : True # form.cleaned_data['cc_myself']
352             }
353
354             recipients = authority_get_pi_emails(authority_hrn)
355             if ctx['cc_myself']:
356                 recipients.append(ctx['email'])
357
358             msg = render_to_string('user_request_email.txt', ctx)
359             send_mail("Onelab New User request submitted", msg, email, recipients)
360
361             return render(request, 'user_register_complete.html')
362
363     return render(request, 'register_4m_f4f.html',{
364         'topmenu_items': topmenu_items('Register', request),
365         'errors': errors,
366         'firstname': request.POST.get('firstname', ''),
367         'lastname': request.POST.get('lastname', ''),
368         'affiliation': request.POST.get('affiliation', ''),
369         'authority_hrn': request.POST.get('authority_hrn', ''),
370         'email': request.POST.get('email', ''),
371         'password': request.POST.get('password', ''),           
372         'authorities': authorities
373     })        
374     
375
376 # view for contact form
377 def contact(request):
378     if request.method == 'POST': # If the form has been submitted...
379         form = ContactForm(request.POST) # A form bound to the POST data
380         if form.is_valid(): # All validation rules pass
381             # Process the data in form.cleaned_data
382             first_name = form.cleaned_data['first_name']
383             last_name = form.cleaned_data['last_name']
384             affiliation = form.cleaned_data['affiliation']
385             subject = form.cleaned_data['subject']
386             message = form.cleaned_data['message']
387             email = form.cleaned_data['email'] # email of the sender
388             cc_myself = form.cleaned_data['cc_myself']
389
390             #recipients = authority_get_pi_emails(authority_hrn)
391             recipients = ['yasin.upmc@gmail.com']
392             if cc_myself:
393                 recipients.append(email)
394
395             from django.core.mail import send_mail
396             send_mail("Onelab user submitted a query ", [first_name,last_name,affiliation,subject,message], email, recipients)
397             return render(request,'contact_sent.html') # Redirect after POST
398     else:
399         form = ContactForm() # An unbound form
400     
401     return render(request, 'contact.html', {
402         'form': form,
403         'topmenu_items': topmenu_items('Contact Us', request),
404         'username': the_user (request)
405
406     })
407
408 @login_required
409 def slice_request(request):
410     errors = []
411
412     authorities_query = Query.get('authority').filter_by('authority_hrn', 'included', ['ple.inria', 'ple.upmc']).select('name', 'authority_hrn')
413     #authorities_query = Query.get('authority').select('authority_hrn')
414     authorities = execute_query(request, authorities_query)
415
416     authority_hrn_tuple = []
417     for authority in authorities:
418         authority_hrn_tuple.append((authority['authority_hrn'], authority['name']))
419     authority_hrn_initial = {'authority_hrn': authority_hrn_tuple}
420         
421     # request.POST or None ?
422     if request.method == 'POST':
423         # The form has been submitted
424         form = SliceRequestForm(request.POST, initial=authority_hrn_initial) 
425
426         if form.is_valid():
427             slice_name      = form.cleaned_data['slice_name']
428             authority_hrn   = form.cleaned_data['authority_hrn']
429             number_of_nodes = form.cleaned_data['number_of_nodes']
430             type_of_nodes   = form.cleaned_data['type_of_nodes']
431             purpose         = form.cleaned_data['purpose']
432             
433             s = PendingSlice(
434                 slice_name      = slice_name,
435                 authority_hrn   = authority_hrn,
436                 number_of_nodes = number_of_nodes,
437                 type_of_nodes   = type_of_nodes,
438                 purpose         = purpose
439             )
440             s.save()
441
442             # All validation rules pass; process data in form.cleaned_data
443             # slice_name, number_of_nodes, type_of_nodes, purpose
444             email = form.cleaned_data['email'] # email of the sender
445             cc_myself = form.cleaned_data['cc_myself']
446
447             # The recipients are the PI of the authority
448             recipients = authority_get_pi_emails(authority_hrn)
449             #recipients = ['yasin.upmc@gmail.com','jordan.auge@lip6.fr']
450             if cc_myself:
451                 recipients.append(email)
452             msg = render_to_string('slice_request_email.txt', form.cleaned_data)
453             send_mail("Onelab New Slice request form submitted", msg, email, recipients)
454
455             return render(request,'slicereq_recvd.html') # Redirect after POST
456     else:
457         form = SliceRequestForm(initial=authority_hrn_initial)
458
459 #    template_env = {}
460 #    template_env['form'] = form
461 #    template_env['topmenu_items'] = topmenu_items('Request a slice', request) 
462 #    template_env['unfold1_main'] = render(request, 'slice_request_.html', {
463 #        'form': form,
464 #    })
465 #    from django.shortcuts                import render_to_response
466 #    from django.template                 import RequestContext
467 #    return render_to_response ('view-unfold1.html',template_env,
468 #                               context_instance=RequestContext(request))
469
470     return render(request, 'slice_request.html', {
471         'form': form,
472         'topmenu_items': topmenu_items('Request a slice', request),
473         'username': the_user (request) 
474     })
475
476
477 class PresViewView(TemplateView):
478     template_name = "view-unfold1.html"
479
480     def get_context_data(self, **kwargs):
481
482         page = Page(self.request)
483
484         pres_view = PresView(page = page)
485
486         context = super(PresViewView, self).get_context_data(**kwargs)
487
488         #context['ALL_STATIC'] = "all_static"
489         context['unfold1_main'] = pres_view.render(self.request)
490
491         # XXX This is repeated in all pages
492         # more general variables expected in the template
493         context['title'] = 'Test view that combines various plugins'
494         # the menu items on the top
495         context['topmenu_items'] = topmenu_items('PresView', self.request)
496         # so we can sho who is logged
497         context['username'] = the_user(self.request)
498
499         prelude_env = page.prelude_env()
500         context.update(prelude_env)
501
502         return context
503
504 def json_me(config_file,type):
505     json_answer = ''
506     for ligne in config_file:
507         if not ligne.startswith('#'):
508             args = ligne.split(';')
509             json_answer += str('{ "name": "' + args[0] + '" ,"id":"' + args[1]  + '" ,"descriptif":"' + args[2]+'"')
510             if type!="dynamic":
511                 json_answer += str(',"contraints":')
512                 if args[3]=="":
513                     json_answer += str('""')
514                 else:
515                     json_answer += str(args[3])
516             json_answer += str('},')
517     return json_answer[:-1]
518
519
520 DIR = '/var/myslice/'
521 STATIC = '%s/config_method_static' % DIR
522 DYNAMIC = '%s/config_method_dynamic' % DIR
523 ANIMATION = '%s/config_method_animation' % DIR
524
525 def pres_view_methods(request, type):
526
527     if type ==None:
528         return 0
529     elif type =="static":
530         config = open(STATIC, "r")
531         json_answer = str('{ "options": [')
532         json_answer += str(json_me(config,"static"))
533         json_answer += str('] }')
534         config.close()
535     elif type =="dynamic":
536         config = open(DYNAMIC, "r")
537         json_answer = str('{ "options": [')
538         json_answer += str(json_me(config,"dynamic"))
539         json_answer += str('] }')
540         config.close()
541     elif type =="animation":
542         config = open(ANIMATION, "r")
543         json_answer = str('{ "options": [')
544         json_answer += str(json_me(config,"animation"))
545         json_answer += str('] }')
546         config.close()
547     elif type =="all":
548         config = open(STATIC, "r")
549         json_answer = str('{ "static": [')
550         json_answer += str(json_me(config,"static"))
551         json_answer += str('],')
552         json_answer += str('"dynamic": [')
553         config.close()
554         config = open(DYNAMIC, "r")
555         json_answer += str(json_me(config,"dynamic"))
556         json_answer += str('],')
557         json_answer += str('"animation": [')
558         config.close()
559         config = open(ANIMATION, "r")
560         json_answer += str(json_me(config,"animation"))
561         json_answer += str('] }')
562         config.close()
563     else:
564         return 0
565     return HttpResponse (json_answer, mimetype="application/json")
566
567 def pres_view_animation(request, constraints, id):
568
569 # sites crees depuis 2008
570 # static.py?contraints=']date_created':1262325600&id='name_id"'
571
572     # method = request.getvalue('method') #ex : GetSites
573     #constraints = "']date_created':1262325600"
574     #id = "2"
575
576     if id == None:
577         return 0
578
579     # method = 'GetSites'#request.getvalue('method') #ex : GetSites
580     # constraints = {}#request.getvalue('constraints') // nul = {}
581     # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
582
583     config_file = open(ANIMATION, "r")
584     for ligne in config_file:
585         if not ligne.startswith('#'):
586             ligne = ligne.split('\n')
587             first = ligne[0].split(';')
588             if (str(first[1]) == str(id)):
589                 save = first
590     config_file.close()
591
592     #Les print_method, print_option sont definis par le client (js)
593     #Les animations acceptent que les connexions anonymous
594     # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
595     args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
596
597
598     #Creation d'un objet event
599     event = Event(args)
600     cmd = [{"params": {
601             "data": {
602                 "print_options": event.print_options,
603                 "print_method": event.print_method,
604                 "message": event.data
605             }
606         }
607     }]
608
609     json_answer = json.dumps(cmd)
610     return HttpResponse (json_answer, mimetype="application/json")
611
612 def pres_view_static(request, constraints, id):
613     #constraints = "']date_created':1262325600"
614     #id = "2"
615
616     # method = 'GetSites'#request.getvalue('method') #ex : GetSites
617     # constraints = {}#request.getvalue('constraints') // nul = {}
618     # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
619
620     config_file = open(STATIC, "r")
621     for ligne in config_file:
622         if not ligne.startswith('#'):
623             ligne = ligne.split('\n')
624             first = ligne[0].split(';')
625             if (str(first[1]) == str(id)):
626                 save = first
627     config_file.close()
628
629     #Les print_method, print_option sont definis par le client (js)
630     #Les animations acceptent que les connexions anonymous
631     # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
632     args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
633
634
635     #Creation d'un objet event
636     event = Event(args)
637     cmd = [{"params": {
638             "data": {
639                 "print_options": event.print_options,
640                 "print_method": event.print_method,
641                 "message": event.data
642             }
643         }
644     }]
645
646     json_answer = json.dumps(cmd)
647     return HttpResponse (json_answer, mimetype="application/json")
648
649 class ValidatePendingView(TemplateView):
650     template_name = "validate_pending.html"
651
652     def get_context_data(self, **kwargs):
653         # We might have slices on different registries with different user accounts 
654         # 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
655         # Different registries mean different identities, unless we identify via SFA HRN or have associated the user email to a single hrn
656
657         #messages.info(self.request, 'You have logged in')
658         page = Page(self.request)
659
660         ctx_my_authorities = {}
661         ctx_delegation_authorities = {}
662
663
664         # The user need to be logged in
665         if the_user(self.request):
666             # Who can a PI validate:
667             # His own authorities + those he has credentials for.
668             # In MySlice we need to look at credentials also.
669             
670
671             # XXX This will have to be asynchroneous. Need to implement barriers,
672             # for now it will be sufficient to have it working statically
673
674             # get user_id to later on query accounts
675             # XXX Having real query plan on local tables would simplify all this
676             # XXX $user_email is still not available for local tables
677             #user_query = Query().get('local:user').filter_by('email', '==', '$user_email').select('user_id')
678             user_query = Query().get('local:user').filter_by('email', '==', the_user(self.request)).select('user_id')
679             user, = execute_query(self.request, user_query)
680             user_id = user['user_id']
681
682             # Query manifold to learn about available SFA platforms for more information
683             # In general we will at least have the portal
684             # For now we are considering all registries
685             all_authorities = []
686             platform_ids = []
687             sfa_platforms_query = Query().get('local:platform').filter_by('gateway_type', '==', 'sfa').select('platform_id', 'platform', 'auth_type')
688             sfa_platforms = execute_query(self.request, sfa_platforms_query)
689             for sfa_platform in sfa_platforms:
690                 print "SFA PLATFORM > ", sfa_platform['platform']
691                 if not 'auth_type' in sfa_platform:
692                     continue
693                 auth = sfa_platform['auth_type']
694                 if not auth in all_authorities:
695                     all_authorities.append(auth)
696                 platform_ids.append(sfa_platform['platform_id'])
697
698             # We can check on which the user has authoritity credentials = PI rights
699             credential_authorities = set()
700             credential_authorities_expired = set()
701
702             # User account on these registries
703             user_accounts_query = Query.get('local:account').filter_by('user_id', '==', user_id).filter_by('platform_id', 'included', platform_ids).select('config')
704             user_accounts = execute_query(self.request, user_accounts_query)
705             #print "=" * 80
706             #print user_accounts
707             #print "=" * 80
708             for user_account in user_accounts:
709                 config = json.loads(user_account['config'])
710                 creds = []
711                 if 'authority_credentials' in config:
712                     for authority_hrn, credential in config['authority_credentials'].items():
713                         #if credential is not expired:
714                         credential_authorities.add(authority_hrn)
715                         #else
716                         #    credential_authorities_expired.add(authority_hrn)
717                 if 'delegated_authority_credentials' in config:
718                     for authority_hrn, credential in config['delegated_authority_credentials'].items():
719                         #if credential is not expired:
720                         credential_authorities.add(authority_hrn)
721                         #else
722                         #    credential_authorities_expired.add(authority_hrn)
723
724             print 'credential_authorities =', credential_authorities
725             print 'credential_authorities_expired =', credential_authorities_expired
726
727             # ** Where am I a PI **
728             # For this we need to ask SFA (of all authorities) = PI function
729             pi_authorities_query = Query.get('user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
730             pi_authorities_tmp = execute_query(self.request, pi_authorities_query)
731             pi_authorities = set()
732             for pa in pi_authorities_tmp:
733                 pi_authorities |= set(pa['pi_authorities'])
734
735             print "pi_authorities =", pi_authorities
736             
737             # My authorities + I have a credential
738             pi_credential_authorities = pi_authorities & credential_authorities
739             pi_no_credential_authorities = pi_authorities - credential_authorities - credential_authorities_expired
740             pi_expired_credential_authorities = pi_authorities & credential_authorities_expired
741             # Authorities I've been delegated PI rights
742             pi_delegation_credential_authorities = credential_authorities - pi_authorities
743             pi_delegation_expired_authorities = credential_authorities_expired - pi_authorities
744
745             print "pi_credential_authorities =", pi_credential_authorities
746             print "pi_no_credential_authorities =", pi_no_credential_authorities
747             print "pi_expired_credential_authorities =", pi_expired_credential_authorities
748             print "pi_delegation_credential_authorities = ", pi_delegation_credential_authorities
749             print "pi_delegation_expired_authorities = ", pi_delegation_expired_authorities
750
751             # Summary intermediary
752             pi_my_authorities = pi_credential_authorities | pi_no_credential_authorities | pi_expired_credential_authorities
753             pi_delegation_authorities = pi_delegation_credential_authorities | pi_delegation_expired_authorities
754
755             print "--"
756             print "pi_my_authorities = ", pi_my_authorities
757             print "pi_delegation_authorities = ", pi_delegation_authorities
758
759             # Summary all
760             queried_pending_authorities = pi_my_authorities | pi_delegation_authorities
761             print "----"
762             print "queried_pending_authorities = ", queried_pending_authorities
763
764             requests = get_request_by_authority(queried_pending_authorities)
765             for request in requests:
766                 auth_hrn = request['authority_hrn']
767
768                 if auth_hrn in pi_my_authorities:
769                     dest = ctx_my_authorities
770
771                     # define the css class
772                     if auth_hrn in pi_credential_authorities:
773                         request['allowed'] = 'allowed'
774                     elif auth_hrn in pi_expired_credential_authorities:
775                         request['allowed'] = 'expired'
776                     else: # pi_no_credential_authorities
777                         request['allowed'] = 'denied'
778
779                 elif auth_hrn in pi_delegation_authorities:
780                     dest = ctx_delegation_authorities
781
782                     if auth_hrn in pi_delegation_credential_authorities:
783                         request['allowed'] = 'allowed'
784                     else: # pi_delegation_expired_authorities
785                         request['allowed'] = 'expired'
786
787                 else:
788                     continue
789
790                 if not auth_hrn in dest:
791                     dest[auth_hrn] = []
792                 dest[auth_hrn].append(request) 
793         
794         context = super(ValidatePendingView, self).get_context_data(**kwargs)
795         context['my_authorities']   = ctx_my_authorities
796         context['delegation_authorities'] = ctx_delegation_authorities
797
798         # XXX This is repeated in all pages
799         # more general variables expected in the template
800         context['title'] = 'Test view that combines various plugins'
801         # the menu items on the top
802         context['topmenu_items'] = topmenu_items('Dashboard', self.request) 
803         # so we can sho who is logged
804         context['username'] = the_user(self.request) 
805
806         # XXX We need to prepare the page for queries
807         #context.update(page.prelude_env())
808
809         return context