platformsview.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 ['affiliation'] = config.get('affiliation',"Unknown Affiliation")
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
192
193
194
195
196 @login_required
197 # View for my_account form
198 #def my_account(request):
199 #    return render(request, 'my_account.html', {
200 #        #'form': form,
201 #        'topmenu_items': topmenu_items('My Account', request),
202 #        'username': the_user (request)
203 #    })
204
205
206 @login_required
207 #my_acc form value processing
208 def account_process(request):
209     # getting the user_id from the session [now hardcoded]
210     get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
211     # getting user info from manifold
212     if 'submit_name' in request.POST:
213         edited_first_name =  request.POST['fname']
214         edited_last_name =  request.POST['lname']
215         #email = 'test_email@gmail.com'
216         #password = 'test_pp'
217         #message = 'F_Name: %s L_name: %s dummy_pp: %s' % (first_name, last_name, password)
218         #site = None
219         
220         # insert into DB [needed for registration page]
221         #approach borrowed from register view     
222         #new_user = PendingUser.objects.create_inactive_user(edited_first_name, edited_last_name, email,  password, site) 
223         #conventional approach
224         #b = PendingUser(first_name=edited_first_name, last_name=edited_last_name)
225         #b.save()
226         
227         # select and update [will be used throughout this view]
228         # select the logged in user [for the moment hard coded]
229         #get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
230         # update first and last name
231         #get_user.first_name = edited_first_name
232         #get_user.last_name = edited_last_name
233         #get_user.save()
234         #user_params = {'config':'hello'}
235         #query = Query.update('local:user').set(user_params).select('config')
236         #results = execute_query(request,query)
237         #if not results:
238         #    raise Exception, "Failed to update user: %s" % user_params['config']
239         #result, = results
240         #return result['config']
241         # create user is working fine :)
242         #user_params = ({'config':'"firstname":"HELLO"'},{'password':'hello'})
243         #user_params = { 'config':'{"firstname":"HEY"}'}
244         #user_params = {'email':'aa@aa.com','password':'demo'}
245         #manifold_add_user(request,user_params)        
246         #manifold_update_user(request,user_params)
247
248         return HttpResponse('Sucess: First Name and Last Name Updated!')       
249     elif 'submit_pass' in request.POST:
250         edited_password = request.POST['password']
251         # select the logged in user [for the moment hard coded]
252         #get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
253         # update password
254         get_user.password = edited_password
255         get_user.save()
256         return HttpResponse('Success: Password Changed!!')
257     elif 'generate' in request.POST:
258         # Generate public and private keys using SFA Library
259         from sfa.trust.certificate  import Keypair
260         k = Keypair(create=True)
261         public_key = k.get_pubkey_string()
262         private_key = k.as_pem()
263        
264 # DEPRECATED
265 #        KEY_LENGTH = 2048
266 #
267 #        def blank_callback():
268 #            "Replace the default dashes"
269 #            return
270 #
271 #        # Random seed
272 #        Rand.rand_seed (os.urandom (KEY_LENGTH))
273 #        # Generate key pair
274 #        key = RSA.gen_key (KEY_LENGTH, 65537, blank_callback)
275 #        # Create memory buffers
276 #        pri_mem = BIO.MemoryBuffer()
277 #        pub_mem = BIO.MemoryBuffer()
278 #        # Save keys to buffers
279 #        key.save_key_bio(pri_mem, None)
280 #        key.save_pub_key_bio(pub_mem)
281 #
282 #        # Get keys 
283 #        public_key = pub_mem.getvalue()
284 #        private_key = pri_mem.getvalue()
285         private_key = ''.join(private_key.split())
286         public_key = "ssh-rsa " + public_key
287         # Saving to DB
288         keypair = '{"user_public_key":"'+ public_key + '", "user_private_key":"'+ private_key + '"}'
289 #        keypair = re.sub("\r", "", keypair)
290 #        keypair = re.sub("\n", "\\n", keypair)
291 #        #keypair = keypair.rstrip('\r\n')
292 #        keypair = ''.join(keypair.split())
293         get_user.keypair = keypair
294         get_user.save()
295         return HttpResponse('Success: New Keypair Generated! %s' % keypair)
296
297     elif 'upload_key' in request.POST:
298         up_file = request.FILES['pubkey']
299         file_content =  up_file.read()
300         file_name = up_file.name
301         file_extension = os.path.splitext(file_name)[1] 
302         allowed_extension =  ['.pub','.txt']
303         if file_extension in allowed_extension and re.search(r'ssh-rsa',file_content):
304             file_content = '{"user_public_key":"'+ file_content +'"}'
305             file_content = re.sub("\r", "", file_content)
306             file_content = re.sub("\n", "\\n",file_content)
307             file_content = ''.join(file_content.split())
308             get_user.keypair = file_content
309             get_user.save()
310             return HttpResponse('Success: Publickey uploaded! Old records overwritten')
311         else:
312             return HttpResponse('Please upload a valid RSA public key [.txt or .pub].')    
313         
314     else:
315         message = 'You submitted an empty form.'
316         return HttpResponse(message)
317
318 def register_4m_f4f(request):
319     errors = []
320
321     authorities_query = Query.get('authority').filter_by('authority_hrn', 'included', ['ple.inria', 'ple.upmc']).select('name', 'authority_hrn')
322     #authorities_query = Query.get('authority').select('authority_hrn')
323     authorities = execute_query(request, authorities_query)
324
325     if request.method == 'POST':
326         # We shall use a form here
327
328         #get_email = PendingUser.objects.get(email)
329         reg_fname = request.POST.get('firstname', '')
330         reg_lname = request.POST.get('lastname', '')
331         reg_aff = request.POST.get('affiliation','')
332         reg_auth = request.POST.get('authority_hrn', '')
333         reg_email = request.POST.get('email','').lower()
334         
335         #POST value validation  
336         if (re.search(r'^[\w+\s.@+-]+$', reg_fname)==None):
337             errors.append('First Name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
338             #return HttpResponse("Only Letters, Numbers, - and _ allowd in First Name")
339             #return render(request, 'register_4m_f4f.html')
340         if (re.search(r'^[\w+\s.@+-]+$', reg_lname) == None):
341             errors.append('Last Name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
342             #return HttpResponse("Only Letters, Numbers, - and _ is allowed in Last name")
343             #return render(request, 'register_4m_f4f.html')
344         if (re.search(r'^[\w+\s.@+-]+$', reg_aff) == None):
345             errors.append('Affiliation may contain only letters, numbers, spaces and @/./+/-/_ characters.')
346             #return HttpResponse("Only Letters, Numbers and _ is allowed in Affiliation")
347             #return render(request, 'register_4m_f4f.html')
348         # XXX validate authority hrn !!
349         if PendingUser.objects.filter(email__iexact=reg_email):
350             errors.append('Email already registered.Please provide a new email address.')
351             #return HttpResponse("Email Already exists")
352             #return render(request, 'register_4m_f4f.html')
353         if 'generate' in request.POST['question']:
354             # Generate public and private keys using SFA Library
355             from sfa.trust.certificate  import Keypair
356             k = Keypair(create=True)
357             public_key = k.get_pubkey_string()
358             private_key = k.as_pem()
359
360 # DEPRECATED
361 #            #import os
362 #            #from M2Crypto import Rand, RSA, BIO
363 #            
364 #            KEY_LENGTH = 2048
365 #
366 #            def blank_callback():
367 #                "Replace the default dashes"
368 #                return
369 #
370 #            # Random seed
371 #            Rand.rand_seed (os.urandom (KEY_LENGTH))
372 #            # Generate key pair
373 #            key = RSA.gen_key (KEY_LENGTH, 65537, blank_callback)
374 #            # Create memory buffers
375 #            pri_mem = BIO.MemoryBuffer()
376 #            pub_mem = BIO.MemoryBuffer()
377 #            # Save keys to buffers
378 #            key.save_key_bio(pri_mem, None)
379 #            key.save_pub_key_bio(pub_mem)
380 #            # Get keys 
381 #            public_key = pub_mem.getvalue()
382 #            private_key = pri_mem.getvalue()
383
384             private_key = ''.join(private_key.split())
385             public_key = "ssh-rsa " + public_key
386             # Saving to DB
387             keypair = '{"user_public_key":"'+ public_key + '", "user_private_key":"'+ private_key + '"}'
388 #            keypair = re.sub("\r", "", keypair)
389 #            keypair = re.sub("\n", "\\n", keypair)
390 #            #keypair = keypair.rstrip('\r\n')
391 #            keypair = ''.join(keypair.split())
392         else:
393             up_file = request.FILES['user_public_key']
394             file_content =  up_file.read()
395             file_name = up_file.name
396             file_extension = os.path.splitext(file_name)[1]
397             allowed_extension =  ['.pub','.txt']
398             if file_extension in allowed_extension and re.search(r'ssh-rsa',file_content):
399                 keypair = '{"user_public_key":"'+ file_content +'"}'
400                 keypair = re.sub("\r", "", keypair)
401                 keypair = re.sub("\n", "\\n",keypair)
402                 keypair = ''.join(keypair.split())
403             else:
404                 errors.append('Please upload a valid RSA public key [.txt or .pub].')
405
406         #b = PendingUser(first_name=reg_fname, last_name=reg_lname, affiliation=reg_aff, 
407         #                email=reg_email, password=request.POST['password'], keypair=keypair)
408         #b.save()
409         if not errors:
410             b = PendingUser(
411                 first_name=reg_fname, 
412                 last_name=reg_lname, 
413                 affiliation=reg_aff,
414                 authority_hrn=reg_auth,
415                 email=reg_email, 
416                 password=request.POST['password'],
417                 keypair=keypair
418             )
419             b.save()
420
421             # Send email
422             ctx = {
423                 first_name   : reg_fname, 
424                 last_name    : reg_lname, 
425                 affiliation  : reg_aff,
426                 authority_hrn: reg_auth,
427                 email        : reg_email, 
428                 keypair      : keypair,
429                 cc_myself    : True # form.cleaned_data['cc_myself']
430             }
431
432             recipients = authority_get_pi_emails(authority_hrn)
433             if ctx['cc_myself']:
434                 recipients.append(ctx['email'])
435
436             msg = render_to_string('user_request_email.txt', ctx)
437             send_mail("Onelab New User request submitted", msg, email, recipients)
438
439             return render(request, 'user_register_complete.html')
440
441     return render(request, 'register_4m_f4f.html',{
442         'topmenu_items': topmenu_items('Register', request),
443         'errors': errors,
444         'firstname': request.POST.get('firstname', ''),
445         'lastname': request.POST.get('lastname', ''),
446         'affiliation': request.POST.get('affiliation', ''),
447         'authority_hrn': request.POST.get('authority_hrn', ''),
448         'email': request.POST.get('email', ''),
449         'password': request.POST.get('password', ''),           
450         'authorities': authorities
451     })        
452     
453
454 # view for contact form
455 def contact(request):
456     if request.method == 'POST': # If the form has been submitted...
457         form = ContactForm(request.POST) # A form bound to the POST data
458         if form.is_valid(): # All validation rules pass
459             # Process the data in form.cleaned_data
460             first_name = form.cleaned_data['first_name']
461             last_name = form.cleaned_data['last_name']
462             affiliation = form.cleaned_data['affiliation']
463             subject = form.cleaned_data['subject']
464             message = form.cleaned_data['message']
465             email = form.cleaned_data['email'] # email of the sender
466             cc_myself = form.cleaned_data['cc_myself']
467
468             #recipients = authority_get_pi_emails(authority_hrn)
469             recipients = ['yasin.upmc@gmail.com']
470             if cc_myself:
471                 recipients.append(email)
472
473             from django.core.mail import send_mail
474             send_mail("Onelab user submitted a query ", [first_name,last_name,affiliation,subject,message], email, recipients)
475             return render(request,'contact_sent.html') # Redirect after POST
476     else:
477         form = ContactForm() # An unbound form
478     
479     return render(request, 'contact.html', {
480         'form': form,
481         'topmenu_items': topmenu_items('Contact Us', request),
482         'username': the_user (request)
483
484     })
485
486 @login_required
487 def slice_request(request):
488     errors = []
489
490     authorities_query = Query.get('authority').filter_by('authority_hrn', 'included', ['ple.inria', 'ple.upmc']).select('name', 'authority_hrn')
491     #authorities_query = Query.get('authority').select('authority_hrn')
492     authorities = execute_query(request, authorities_query)
493
494     authority_hrn_tuple = []
495     for authority in authorities:
496         authority_hrn_tuple.append((authority['authority_hrn'], authority['name']))
497     authority_hrn_initial = {'authority_hrn': authority_hrn_tuple}
498         
499     # request.POST or None ?
500     if request.method == 'POST':
501         # The form has been submitted
502         form = SliceRequestForm(request.POST, initial=authority_hrn_initial) 
503
504         if form.is_valid():
505             slice_name      = form.cleaned_data['slice_name']
506             authority_hrn   = form.cleaned_data['authority_hrn']
507             number_of_nodes = form.cleaned_data['number_of_nodes']
508             type_of_nodes   = form.cleaned_data['type_of_nodes']
509             purpose         = form.cleaned_data['purpose']
510             
511             s = PendingSlice(
512                 slice_name      = slice_name,
513                 authority_hrn   = authority_hrn,
514                 number_of_nodes = number_of_nodes,
515                 type_of_nodes   = type_of_nodes,
516                 purpose         = purpose
517             )
518             s.save()
519
520             # All validation rules pass; process data in form.cleaned_data
521             # slice_name, number_of_nodes, type_of_nodes, purpose
522             email = form.cleaned_data['email'] # email of the sender
523             cc_myself = form.cleaned_data['cc_myself']
524
525             # The recipients are the PI of the authority
526             recipients = authority_get_pi_emails(authority_hrn)
527             #recipients = ['yasin.upmc@gmail.com','jordan.auge@lip6.fr']
528             if cc_myself:
529                 recipients.append(email)
530             msg = render_to_string('slice_request_email.txt', form.cleaned_data)
531             send_mail("Onelab New Slice request form submitted", msg, email, recipients)
532
533             return render(request,'slicereq_recvd.html') # Redirect after POST
534     else:
535         form = SliceRequestForm(initial=authority_hrn_initial)
536
537 #    template_env = {}
538 #    template_env['form'] = form
539 #    template_env['topmenu_items'] = topmenu_items('Request a slice', request) 
540 #    template_env['unfold1_main'] = render(request, 'slice_request_.html', {
541 #        'form': form,
542 #    })
543 #    from django.shortcuts                import render_to_response
544 #    from django.template                 import RequestContext
545 #    return render_to_response ('view-unfold1.html',template_env,
546 #                               context_instance=RequestContext(request))
547
548     return render(request, 'slice_request.html', {
549         'form': form,
550         'topmenu_items': topmenu_items('Request a slice', request),
551         'username': the_user (request) 
552     })
553
554
555 class PresViewView(TemplateView):
556     template_name = "view-unfold1.html"
557
558     def get_context_data(self, **kwargs):
559
560         page = Page(self.request)
561
562         pres_view = PresView(page = page)
563
564         context = super(PresViewView, self).get_context_data(**kwargs)
565
566         #context['ALL_STATIC'] = "all_static"
567         context['unfold1_main'] = pres_view.render(self.request)
568
569         # XXX This is repeated in all pages
570         # more general variables expected in the template
571         context['title'] = 'Test view that combines various plugins'
572         # the menu items on the top
573         context['topmenu_items'] = topmenu_items('PresView', self.request)
574         # so we can sho who is logged
575         context['username'] = the_user(self.request)
576
577         prelude_env = page.prelude_env()
578         context.update(prelude_env)
579
580         return context
581
582 def json_me(config_file,type):
583     json_answer = ''
584     for ligne in config_file:
585         if not ligne.startswith('#'):
586             args = ligne.split(';')
587             json_answer += str('{ "name": "' + args[0] + '" ,"id":"' + args[1]  + '" ,"descriptif":"' + args[2]+'"')
588             if type!="dynamic":
589                 json_answer += str(',"contraints":')
590                 if args[3]=="":
591                     json_answer += str('""')
592                 else:
593                     json_answer += str(args[3])
594             json_answer += str('},')
595     return json_answer[:-1]
596
597
598 DIR = '/var/myslice/'
599 STATIC = '%s/config_method_static' % DIR
600 DYNAMIC = '%s/config_method_dynamic' % DIR
601 ANIMATION = '%s/config_method_animation' % DIR
602
603 def pres_view_methods(request, type):
604
605     if type ==None:
606         return 0
607     elif type =="static":
608         config = open(STATIC, "r")
609         json_answer = str('{ "options": [')
610         json_answer += str(json_me(config,"static"))
611         json_answer += str('] }')
612         config.close()
613     elif type =="dynamic":
614         config = open(DYNAMIC, "r")
615         json_answer = str('{ "options": [')
616         json_answer += str(json_me(config,"dynamic"))
617         json_answer += str('] }')
618         config.close()
619     elif type =="animation":
620         config = open(ANIMATION, "r")
621         json_answer = str('{ "options": [')
622         json_answer += str(json_me(config,"animation"))
623         json_answer += str('] }')
624         config.close()
625     elif type =="all":
626         config = open(STATIC, "r")
627         json_answer = str('{ "static": [')
628         json_answer += str(json_me(config,"static"))
629         json_answer += str('],')
630         json_answer += str('"dynamic": [')
631         config.close()
632         config = open(DYNAMIC, "r")
633         json_answer += str(json_me(config,"dynamic"))
634         json_answer += str('],')
635         json_answer += str('"animation": [')
636         config.close()
637         config = open(ANIMATION, "r")
638         json_answer += str(json_me(config,"animation"))
639         json_answer += str('] }')
640         config.close()
641     else:
642         return 0
643     return HttpResponse (json_answer, mimetype="application/json")
644
645 def pres_view_animation(request, constraints, id):
646
647 # sites crees depuis 2008
648 # static.py?contraints=']date_created':1262325600&id='name_id"'
649
650     # method = request.getvalue('method') #ex : GetSites
651     #constraints = "']date_created':1262325600"
652     #id = "2"
653
654     if id == None:
655         return 0
656
657     # method = 'GetSites'#request.getvalue('method') #ex : GetSites
658     # constraints = {}#request.getvalue('constraints') // nul = {}
659     # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
660
661     config_file = open(ANIMATION, "r")
662     for ligne in config_file:
663         if not ligne.startswith('#'):
664             ligne = ligne.split('\n')
665             first = ligne[0].split(';')
666             if (str(first[1]) == str(id)):
667                 save = first
668     config_file.close()
669
670     #Les print_method, print_option sont definis par le client (js)
671     #Les animations acceptent que les connexions anonymous
672     # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
673     args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
674
675
676     #Creation d'un objet event
677     event = Event(args)
678     cmd = [{"params": {
679             "data": {
680                 "print_options": event.print_options,
681                 "print_method": event.print_method,
682                 "message": event.data
683             }
684         }
685     }]
686
687     json_answer = json.dumps(cmd)
688     return HttpResponse (json_answer, mimetype="application/json")
689
690 def pres_view_static(request, constraints, id):
691     #constraints = "']date_created':1262325600"
692     #id = "2"
693
694     # method = 'GetSites'#request.getvalue('method') #ex : GetSites
695     # constraints = {}#request.getvalue('constraints') // nul = {}
696     # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
697
698     config_file = open(STATIC, "r")
699     for ligne in config_file:
700         if not ligne.startswith('#'):
701             ligne = ligne.split('\n')
702             first = ligne[0].split(';')
703             if (str(first[1]) == str(id)):
704                 save = first
705     config_file.close()
706
707     #Les print_method, print_option sont definis par le client (js)
708     #Les animations acceptent que les connexions anonymous
709     # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
710     args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
711
712
713     #Creation d'un objet event
714     event = Event(args)
715     cmd = [{"params": {
716             "data": {
717                 "print_options": event.print_options,
718                 "print_method": event.print_method,
719                 "message": event.data
720             }
721         }
722     }]
723
724     json_answer = json.dumps(cmd)
725     return HttpResponse (json_answer, mimetype="application/json")
726
727 class ValidatePendingView(TemplateView):
728     template_name = "validate_pending.html"
729
730     def get_context_data(self, **kwargs):
731         # We might have slices on different registries with different user accounts 
732         # 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
733         # Different registries mean different identities, unless we identify via SFA HRN or have associated the user email to a single hrn
734
735         #messages.info(self.request, 'You have logged in')
736         page = Page(self.request)
737
738         ctx_my_authorities = {}
739         ctx_delegation_authorities = {}
740
741
742         # The user need to be logged in
743         if the_user(self.request):
744             # Who can a PI validate:
745             # His own authorities + those he has credentials for.
746             # In MySlice we need to look at credentials also.
747             
748
749             # XXX This will have to be asynchroneous. Need to implement barriers,
750             # for now it will be sufficient to have it working statically
751
752             # get user_id to later on query accounts
753             # XXX Having real query plan on local tables would simplify all this
754             # XXX $user_email is still not available for local tables
755             #user_query = Query().get('local:user').filter_by('email', '==', '$user_email').select('user_id')
756             user_query = Query().get('local:user').filter_by('email', '==', the_user(self.request)).select('user_id')
757             user, = execute_query(self.request, user_query)
758             user_id = user['user_id']
759
760             # Query manifold to learn about available SFA platforms for more information
761             # In general we will at least have the portal
762             # For now we are considering all registries
763             all_authorities = []
764             platform_ids = []
765             sfa_platforms_query = Query().get('local:platform').filter_by('gateway_type', '==', 'sfa').select('platform_id', 'platform', 'auth_type')
766             sfa_platforms = execute_query(self.request, sfa_platforms_query)
767             for sfa_platform in sfa_platforms:
768                 print "SFA PLATFORM > ", sfa_platform['platform']
769                 if not 'auth_type' in sfa_platform:
770                     continue
771                 auth = sfa_platform['auth_type']
772                 if not auth in all_authorities:
773                     all_authorities.append(auth)
774                 platform_ids.append(sfa_platform['platform_id'])
775
776             # We can check on which the user has authoritity credentials = PI rights
777             credential_authorities = set()
778             credential_authorities_expired = set()
779
780             # User account on these registries
781             user_accounts_query = Query.get('local:account').filter_by('user_id', '==', user_id).filter_by('platform_id', 'included', platform_ids).select('config')
782             user_accounts = execute_query(self.request, user_accounts_query)
783             #print "=" * 80
784             #print user_accounts
785             #print "=" * 80
786             for user_account in user_accounts:
787                 config = json.loads(user_account['config'])
788                 creds = []
789                 if 'authority_credentials' in config:
790                     for authority_hrn, credential in config['authority_credentials'].items():
791                         #if credential is not expired:
792                         credential_authorities.add(authority_hrn)
793                         #else
794                         #    credential_authorities_expired.add(authority_hrn)
795                 if 'delegated_authority_credentials' in config:
796                     for authority_hrn, credential in config['delegated_authority_credentials'].items():
797                         #if credential is not expired:
798                         credential_authorities.add(authority_hrn)
799                         #else
800                         #    credential_authorities_expired.add(authority_hrn)
801
802             print 'credential_authorities =', credential_authorities
803             print 'credential_authorities_expired =', credential_authorities_expired
804
805             # ** Where am I a PI **
806             # For this we need to ask SFA (of all authorities) = PI function
807             pi_authorities_query = Query.get('user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
808             pi_authorities_tmp = execute_query(self.request, pi_authorities_query)
809             pi_authorities = set()
810             for pa in pi_authorities_tmp:
811                 pi_authorities |= set(pa['pi_authorities'])
812
813             print "pi_authorities =", pi_authorities
814             
815             # My authorities + I have a credential
816             pi_credential_authorities = pi_authorities & credential_authorities
817             pi_no_credential_authorities = pi_authorities - credential_authorities - credential_authorities_expired
818             pi_expired_credential_authorities = pi_authorities & credential_authorities_expired
819             # Authorities I've been delegated PI rights
820             pi_delegation_credential_authorities = credential_authorities - pi_authorities
821             pi_delegation_expired_authorities = credential_authorities_expired - pi_authorities
822
823             print "pi_credential_authorities =", pi_credential_authorities
824             print "pi_no_credential_authorities =", pi_no_credential_authorities
825             print "pi_expired_credential_authorities =", pi_expired_credential_authorities
826             print "pi_delegation_credential_authorities = ", pi_delegation_credential_authorities
827             print "pi_delegation_expired_authorities = ", pi_delegation_expired_authorities
828
829             # Summary intermediary
830             pi_my_authorities = pi_credential_authorities | pi_no_credential_authorities | pi_expired_credential_authorities
831             pi_delegation_authorities = pi_delegation_credential_authorities | pi_delegation_expired_authorities
832
833             print "--"
834             print "pi_my_authorities = ", pi_my_authorities
835             print "pi_delegation_authorities = ", pi_delegation_authorities
836
837             # Summary all
838             queried_pending_authorities = pi_my_authorities | pi_delegation_authorities
839             print "----"
840             print "queried_pending_authorities = ", queried_pending_authorities
841
842             requests = get_request_by_authority(queried_pending_authorities)
843             for request in requests:
844                 auth_hrn = request['authority_hrn']
845
846                 if auth_hrn in pi_my_authorities:
847                     dest = ctx_my_authorities
848
849                     # define the css class
850                     if auth_hrn in pi_credential_authorities:
851                         request['allowed'] = 'allowed'
852                     elif auth_hrn in pi_expired_credential_authorities:
853                         request['allowed'] = 'expired'
854                     else: # pi_no_credential_authorities
855                         request['allowed'] = 'denied'
856
857                 elif auth_hrn in pi_delegation_authorities:
858                     dest = ctx_delegation_authorities
859
860                     if auth_hrn in pi_delegation_credential_authorities:
861                         request['allowed'] = 'allowed'
862                     else: # pi_delegation_expired_authorities
863                         request['allowed'] = 'expired'
864
865                 else:
866                     continue
867
868                 if not auth_hrn in dest:
869                     dest[auth_hrn] = []
870                 dest[auth_hrn].append(request) 
871         
872         context = super(ValidatePendingView, self).get_context_data(**kwargs)
873         context['my_authorities']   = ctx_my_authorities
874         context['delegation_authorities'] = ctx_delegation_authorities
875
876         # XXX This is repeated in all pages
877         # more general variables expected in the template
878         context['title'] = 'Test view that combines various plugins'
879         # the menu items on the top
880         context['topmenu_items'] = topmenu_items('Dashboard', self.request) 
881         # so we can sho who is logged
882         context['username'] = the_user(self.request) 
883
884         # XXX We need to prepare the page for queries
885         #context.update(page.prelude_env())
886
887         return context