1 # -*- coding: utf-8 -*-
3 # portal/views.py: views for the portal application
4 # This file is part of the Manifold project.
7 # Jordan Augé <jordan.auge@lip6.fr>
8 # Mohammed Yasin Rahman <mohammed-yasin.rahman@lip6.fr>
9 # Copyright 2013, UPMC Sorbonne Universités / LIP6
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.
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
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.
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
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
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.core.query import Query
47 from manifold.manifoldapi import execute_query
48 from unfold.page import Page
49 from myslice.viewutils import topmenu_items, the_user
50 from django.http import HttpResponseRedirect, HttpResponse
52 from M2Crypto import Rand, RSA, BIO
56 class PlatformsView(TemplateView):
57 template_name = "platforms.html"
59 def get_context_data(self, **kwargs):
60 page = Page(self.request)
62 #network_query = Query().get('local:platform').filter_by('disabled', '==', '0').select('platform','platform_longname','gateway_type')
63 network_query = Query().get('local:platform').select('platform','platform_longname','gateway_type')
64 page.enqueue_query(network_query)
66 page.expose_js_metadata()
68 networklist = Hazelnut(
72 # this is the query at the core of the slice list
73 query = network_query,
74 query_all = network_query,
76 datatables_options = {
77 # for now we turn off sorting on the checkboxes columns this way
78 # this of course should be automatic in hazelnut
79 'aoColumns' : [None, None, None, None, {'bSortable': False}],
80 'iDisplayLength' : 25,
81 'bLengthChange' : True,
85 # networklist = SimpleList(
89 # query = network_query,
92 context = super(PlatformsView, self).get_context_data(**kwargs)
93 context['person'] = self.request.user
94 context['networks'] = networklist.render(self.request)
96 # XXX This is repeated in all pages
97 # more general variables expected in the template
98 context['title'] = 'Platforms connected to MySlice'
99 # the menu items on the top
100 context['topmenu_items'] = topmenu_items('Platforms', self.request)
101 # so we can sho who is logged
102 context['username'] = the_user(self.request)
104 context.update(page.prelude_env())
110 # View for 1 platform and its details
111 class PlatformView(TemplateView):
112 template_name = "platform.html"
114 def get_context_data(self, **kwargs):
115 page = Page(self.request)
117 for key, value in kwargs.iteritems():
118 print "%s = %s" % (key, value)
119 if key == "platformname":
122 network_query = Query().get('local:platform').filter_by('platform', '==', platformname).select('platform','platform_longname','gateway_type')
123 page.enqueue_query(network_query)
125 page.expose_js_metadata()
126 page.expose_queries()
127 networklist = Hazelnut(
130 domid = 'checkboxes',
131 # this is the query at the core of the slice list
132 query = network_query,
133 query_all = network_query,
135 datatables_options = {
136 # for now we turn off sorting on the checkboxes columns this way
137 # this of course should be automatic in hazelnut
138 'aoColumns' : [None, None, None, None, {'bSortable': False}],
139 'iDisplayLength' : 25,
140 'bLengthChange' : True,
144 # networklist = SimpleList(
148 # query = network_query,
151 context = super(PlatformView, self).get_context_data(**kwargs)
152 context['person'] = self.request.user
153 context['networks'] = networklist.render(self.request)
155 # XXX This is repeated in all pages
156 # more general variables expected in the template
157 context['title'] = 'Platforms connected to MySlice'
158 # the menu items on the top
159 context['topmenu_items'] = topmenu_items('Platforms', self.request)
160 # so we can sho who is logged
161 context['username'] = the_user(self.request)
163 context.update(page.prelude_env())
169 #class for my_account
170 class AccountView(TemplateView):
171 template_name = "my_account.html"
173 #This view requires login
174 @method_decorator(login_required)
175 def dispatch(self, *args, **kwargs):
176 return super(AccountView, self).dispatch(*args, **kwargs)
179 def get_context_data(self, **kwargs):
180 #page = Page(self.request)
182 user_query = Query().get('local:user').select('config','email')
183 user_details = execute_query(self.request, user_query)
185 # not always found in user_details...
187 for user_detail in user_details:
188 #email = user_detail['email']
189 if user_detail['config']:
190 config = json.loads(user_detail['config'])
192 platform_query = Query().get('local:platform').select('platform_id','platform')
193 account_query = Query().get('local:account').select('user_id','platform_id','auth_type','config')
194 platform_details = execute_query(self.request, platform_query)
195 account_details = execute_query(self.request, account_query)
197 # initial assignment needed for users having no account
202 platform_name_list = []
203 account_type_list = []
206 for account_detail in account_details:
207 for platform_detail in platform_details:
208 if platform_detail['platform_id'] == account_detail['platform_id']:
209 platform_name = platform_detail['platform']
210 account_type = account_detail['auth_type']
211 account_config = json.loads(account_detail['config'])
212 # a bit more pythonic
213 account_usr_hrn = account_config.get('user_hrn','N/A')
214 account_pub_key = account_config.get('user_public_key','N/A')
216 platform_name_list.append(platform_name)
217 account_type_list.append(account_type)
218 usr_hrn_list.append(account_usr_hrn)
219 pub_key_list.append(account_pub_key)
221 # combining 4 lists into 1 [to render in the template]
222 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)]
226 context = super(AccountView, self).get_context_data(**kwargs)
227 context['data'] = lst
228 context['person'] = self.request.user
229 context ['firstname'] = config.get('firstname',"?")
230 context ['lastname'] = config.get('lastname',"?")
231 context ['fullname'] = context['firstname'] +' '+ context['lastname']
232 context ['affiliation'] = config.get('affiliation',"Unknown Affiliation")
233 #context['users'] = userlist.render(self.request)
235 # XXX This is repeated in all pages
236 # more general variables expected in the template
237 context['title'] = 'Platforms connected to MySlice'
238 # the menu items on the top
239 context['topmenu_items'] = topmenu_items('My Account', self.request)
240 # so we can sho who is logged
241 context['username'] = the_user(self.request)
242 # context ['firstname'] = config['firstname']
243 #context.update(page.prelude_env())
252 # View for my_account form
253 #def my_account(request):
254 # return render(request, 'my_account.html', {
256 # 'topmenu_items': topmenu_items('My Account', request),
257 # 'username': the_user (request)
262 #my_acc form value processing
263 def account_process(request):
264 # getting the user_id from the session [now hardcoded]
265 get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
266 # getting user info from manifold
267 if 'submit_name' in request.POST:
268 edited_first_name = request.POST['fname']
269 edited_last_name = request.POST['lname']
270 #email = 'test_email@gmail.com'
271 #password = 'test_pp'
272 #message = 'F_Name: %s L_name: %s dummy_pp: %s' % (first_name, last_name, password)
275 # insert into DB [needed for registration page]
276 #approach borrowed from register view
277 #new_user = PendingUser.objects.create_inactive_user(edited_first_name, edited_last_name, email, password, site)
278 #conventional approach
279 #b = PendingUser(first_name=edited_first_name, last_name=edited_last_name)
282 # select and update [will be used throughout this view]
283 # select the logged in user [for the moment hard coded]
284 #get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
285 # update first and last name
286 #get_user.first_name = edited_first_name
287 #get_user.last_name = edited_last_name
289 #user_params = {'config':'hello'}
290 #query = Query.update('local:user').set(user_params).select('config')
291 #results = execute_query(request,query)
293 # raise Exception, "Failed to update user: %s" % user_params['config']
295 #return result['config']
296 # create user is working fine :)
297 #user_params = ({'config':'"firstname":"HELLO"'},{'password':'hello'})
298 #user_params = { 'config':'{"firstname":"HEY"}'}
299 #user_params = {'email':'aa@aa.com','password':'demo'}
300 #manifold_add_user(request,user_params)
301 #manifold_update_user(request,user_params)
303 return HttpResponse('Sucess: First Name and Last Name Updated!')
304 elif 'submit_pass' in request.POST:
305 edited_password = request.POST['password']
306 # select the logged in user [for the moment hard coded]
307 #get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
309 get_user.password = edited_password
311 return HttpResponse('Success: Password Changed!!')
312 elif 'generate' in request.POST:
313 # Generate public and private keys using SFA Library
314 from sfa.trust.certificate import Keypair
315 k = Keypair(create=True)
316 public_key = k.get_pubkey_string()
317 private_key = k.as_pem()
322 # def blank_callback():
323 # "Replace the default dashes"
327 # Rand.rand_seed (os.urandom (KEY_LENGTH))
328 # # Generate key pair
329 # key = RSA.gen_key (KEY_LENGTH, 65537, blank_callback)
330 # # Create memory buffers
331 # pri_mem = BIO.MemoryBuffer()
332 # pub_mem = BIO.MemoryBuffer()
333 # # Save keys to buffers
334 # key.save_key_bio(pri_mem, None)
335 # key.save_pub_key_bio(pub_mem)
338 # public_key = pub_mem.getvalue()
339 # private_key = pri_mem.getvalue()
340 private_key = ''.join(private_key.split())
341 public_key = "ssh-rsa " + public_key
343 keypair = '{"user_public_key":"'+ public_key + '", "user_private_key":"'+ private_key + '"}'
344 # keypair = re.sub("\r", "", keypair)
345 # keypair = re.sub("\n", "\\n", keypair)
346 # #keypair = keypair.rstrip('\r\n')
347 # keypair = ''.join(keypair.split())
348 get_user.keypair = keypair
350 return HttpResponse('Success: New Keypair Generated! %s' % keypair)
352 elif 'upload_key' in request.POST:
353 up_file = request.FILES['pubkey']
354 file_content = up_file.read()
355 file_name = up_file.name
356 file_extension = os.path.splitext(file_name)[1]
357 allowed_extension = ['.pub','.txt']
358 if file_extension in allowed_extension and re.search(r'ssh-rsa',file_content):
359 file_content = '{"user_public_key":"'+ file_content +'"}'
360 file_content = re.sub("\r", "", file_content)
361 file_content = re.sub("\n", "\\n",file_content)
362 file_content = ''.join(file_content.split())
363 get_user.keypair = file_content
365 return HttpResponse('Success: Publickey uploaded! Old records overwritten')
367 return HttpResponse('Please upload a valid RSA public key [.txt or .pub].')
370 message = 'You submitted an empty form.'
371 return HttpResponse(message)
373 def register_4m_f4f(request):
376 authorities_query = Query.get('authority').filter_by('authority_hrn', 'included', ['ple.inria', 'ple.upmc']).select('name', 'authority_hrn')
377 #authorities_query = Query.get('authority').select('authority_hrn')
378 authorities = execute_query(request, authorities_query)
380 if request.method == 'POST':
381 # We shall use a form here
383 #get_email = PendingUser.objects.get(email)
384 reg_fname = request.POST.get('firstname', '')
385 reg_lname = request.POST.get('lastname', '')
386 reg_aff = request.POST.get('affiliation','')
387 reg_auth = request.POST.get('authority_hrn', '')
388 reg_email = request.POST.get('email','').lower()
390 #POST value validation
391 if (re.search(r'^[\w+\s.@+-]+$', reg_fname)==None):
392 errors.append('First Name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
393 #return HttpResponse("Only Letters, Numbers, - and _ allowd in First Name")
394 #return render(request, 'register_4m_f4f.html')
395 if (re.search(r'^[\w+\s.@+-]+$', reg_lname) == None):
396 errors.append('Last Name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
397 #return HttpResponse("Only Letters, Numbers, - and _ is allowed in Last name")
398 #return render(request, 'register_4m_f4f.html')
399 if (re.search(r'^[\w+\s.@+-]+$', reg_aff) == None):
400 errors.append('Affiliation may contain only letters, numbers, spaces and @/./+/-/_ characters.')
401 #return HttpResponse("Only Letters, Numbers and _ is allowed in Affiliation")
402 #return render(request, 'register_4m_f4f.html')
403 # XXX validate authority hrn !!
404 if PendingUser.objects.filter(email__iexact=reg_email):
405 errors.append('Email already registered.Please provide a new email address.')
406 #return HttpResponse("Email Already exists")
407 #return render(request, 'register_4m_f4f.html')
408 if 'generate' in request.POST['question']:
409 # Generate public and private keys using SFA Library
410 from sfa.trust.certificate import Keypair
411 k = Keypair(create=True)
412 public_key = k.get_pubkey_string()
413 private_key = k.as_pem()
417 # #from M2Crypto import Rand, RSA, BIO
421 # def blank_callback():
422 # "Replace the default dashes"
426 # Rand.rand_seed (os.urandom (KEY_LENGTH))
427 # # Generate key pair
428 # key = RSA.gen_key (KEY_LENGTH, 65537, blank_callback)
429 # # Create memory buffers
430 # pri_mem = BIO.MemoryBuffer()
431 # pub_mem = BIO.MemoryBuffer()
432 # # Save keys to buffers
433 # key.save_key_bio(pri_mem, None)
434 # key.save_pub_key_bio(pub_mem)
436 # public_key = pub_mem.getvalue()
437 # private_key = pri_mem.getvalue()
439 private_key = ''.join(private_key.split())
440 public_key = "ssh-rsa " + public_key
442 keypair = '{"user_public_key":"'+ public_key + '", "user_private_key":"'+ private_key + '"}'
443 # keypair = re.sub("\r", "", keypair)
444 # keypair = re.sub("\n", "\\n", keypair)
445 # #keypair = keypair.rstrip('\r\n')
446 # keypair = ''.join(keypair.split())
448 up_file = request.FILES['user_public_key']
449 file_content = up_file.read()
450 file_name = up_file.name
451 file_extension = os.path.splitext(file_name)[1]
452 allowed_extension = ['.pub','.txt']
453 if file_extension in allowed_extension and re.search(r'ssh-rsa',file_content):
454 keypair = '{"user_public_key":"'+ file_content +'"}'
455 keypair = re.sub("\r", "", keypair)
456 keypair = re.sub("\n", "\\n",keypair)
457 keypair = ''.join(keypair.split())
459 errors.append('Please upload a valid RSA public key [.txt or .pub].')
461 #b = PendingUser(first_name=reg_fname, last_name=reg_lname, affiliation=reg_aff,
462 # email=reg_email, password=request.POST['password'], keypair=keypair)
466 first_name=reg_fname,
469 authority_hrn=reg_auth,
471 password=request.POST['password'],
478 first_name : reg_fname,
479 last_name : reg_lname,
480 affiliation : reg_aff,
481 authority_hrn: reg_auth,
484 cc_myself : True # form.cleaned_data['cc_myself']
487 recipients = authority_get_pi_emails(authority_hrn)
489 recipients.append(ctx['email'])
491 msg = render_to_string('user_request_email.txt', ctx)
492 send_mail("Onelab New User request submitted", msg, email, recipients)
494 return render(request, 'user_register_complete.html')
496 return render(request, 'register_4m_f4f.html',{
497 'topmenu_items': topmenu_items('Register', request),
499 'firstname': request.POST.get('firstname', ''),
500 'lastname': request.POST.get('lastname', ''),
501 'affiliation': request.POST.get('affiliation', ''),
502 'authority_hrn': request.POST.get('authority_hrn', ''),
503 'email': request.POST.get('email', ''),
504 'password': request.POST.get('password', ''),
505 'authorities': authorities
509 # view for contact form
510 def contact(request):
511 if request.method == 'POST': # If the form has been submitted...
512 form = ContactForm(request.POST) # A form bound to the POST data
513 if form.is_valid(): # All validation rules pass
514 # Process the data in form.cleaned_data
515 first_name = form.cleaned_data['first_name']
516 last_name = form.cleaned_data['last_name']
517 affiliation = form.cleaned_data['affiliation']
518 subject = form.cleaned_data['subject']
519 message = form.cleaned_data['message']
520 email = form.cleaned_data['email'] # email of the sender
521 cc_myself = form.cleaned_data['cc_myself']
523 #recipients = authority_get_pi_emails(authority_hrn)
524 recipients = ['yasin.upmc@gmail.com']
526 recipients.append(email)
528 from django.core.mail import send_mail
529 send_mail("Onelab user submitted a query ", [first_name,last_name,affiliation,subject,message], email, recipients)
530 return render(request,'contact_sent.html') # Redirect after POST
532 form = ContactForm() # An unbound form
534 return render(request, 'contact.html', {
536 'topmenu_items': topmenu_items('Contact Us', request),
537 'username': the_user (request)
542 def slice_request(request):
545 authorities_query = Query.get('authority').filter_by('authority_hrn', 'included', ['ple.inria', 'ple.upmc']).select('name', 'authority_hrn')
546 #authorities_query = Query.get('authority').select('authority_hrn')
547 authorities = execute_query(request, authorities_query)
549 authority_hrn_tuple = []
550 for authority in authorities:
551 authority_hrn_tuple.append((authority['authority_hrn'], authority['name']))
552 authority_hrn_initial = {'authority_hrn': authority_hrn_tuple}
554 # request.POST or None ?
555 if request.method == 'POST':
556 # The form has been submitted
557 form = SliceRequestForm(request.POST, initial=authority_hrn_initial)
560 slice_name = form.cleaned_data['slice_name']
561 authority_hrn = form.cleaned_data['authority_hrn']
562 number_of_nodes = form.cleaned_data['number_of_nodes']
563 type_of_nodes = form.cleaned_data['type_of_nodes']
564 purpose = form.cleaned_data['purpose']
567 slice_name = slice_name,
568 authority_hrn = authority_hrn,
569 number_of_nodes = number_of_nodes,
570 type_of_nodes = type_of_nodes,
575 # All validation rules pass; process data in form.cleaned_data
576 # slice_name, number_of_nodes, type_of_nodes, purpose
577 email = form.cleaned_data['email'] # email of the sender
578 cc_myself = form.cleaned_data['cc_myself']
580 # The recipients are the PI of the authority
581 recipients = authority_get_pi_emails(authority_hrn)
582 #recipients = ['yasin.upmc@gmail.com','jordan.auge@lip6.fr']
584 recipients.append(email)
585 msg = render_to_string('slice_request_email.txt', form.cleaned_data)
586 send_mail("Onelab New Slice request form submitted", msg, email, recipients)
588 return render(request,'slicereq_recvd.html') # Redirect after POST
590 form = SliceRequestForm(initial=authority_hrn_initial)
593 # template_env['form'] = form
594 # template_env['topmenu_items'] = topmenu_items('Request a slice', request)
595 # template_env['unfold1_main'] = render(request, 'slice_request_.html', {
598 # from django.shortcuts import render_to_response
599 # from django.template import RequestContext
600 # return render_to_response ('view-unfold1.html',template_env,
601 # context_instance=RequestContext(request))
603 return render(request, 'slice_request.html', {
605 'topmenu_items': topmenu_items('Request a slice', request),
606 'username': the_user (request)
610 class PresViewView(TemplateView):
611 template_name = "view-unfold1.html"
613 def get_context_data(self, **kwargs):
615 page = Page(self.request)
617 pres_view = PresView(page = page)
619 context = super(PresViewView, self).get_context_data(**kwargs)
621 #context['ALL_STATIC'] = "all_static"
622 context['unfold1_main'] = pres_view.render(self.request)
624 # XXX This is repeated in all pages
625 # more general variables expected in the template
626 context['title'] = 'Test view that combines various plugins'
627 # the menu items on the top
628 context['topmenu_items'] = topmenu_items('PresView', self.request)
629 # so we can sho who is logged
630 context['username'] = the_user(self.request)
632 prelude_env = page.prelude_env()
633 context.update(prelude_env)
637 def json_me(config_file,type):
639 for ligne in config_file:
640 if not ligne.startswith('#'):
641 args = ligne.split(';')
642 json_answer += str('{ "name": "' + args[0] + '" ,"id":"' + args[1] + '" ,"descriptif":"' + args[2]+'"')
644 json_answer += str(',"contraints":')
646 json_answer += str('""')
648 json_answer += str(args[3])
649 json_answer += str('},')
650 return json_answer[:-1]
653 DIR = '/var/myslice/'
654 STATIC = '%s/config_method_static' % DIR
655 DYNAMIC = '%s/config_method_dynamic' % DIR
656 ANIMATION = '%s/config_method_animation' % DIR
658 def pres_view_methods(request, type):
662 elif type =="static":
663 config = open(STATIC, "r")
664 json_answer = str('{ "options": [')
665 json_answer += str(json_me(config,"static"))
666 json_answer += str('] }')
668 elif type =="dynamic":
669 config = open(DYNAMIC, "r")
670 json_answer = str('{ "options": [')
671 json_answer += str(json_me(config,"dynamic"))
672 json_answer += str('] }')
674 elif type =="animation":
675 config = open(ANIMATION, "r")
676 json_answer = str('{ "options": [')
677 json_answer += str(json_me(config,"animation"))
678 json_answer += str('] }')
681 config = open(STATIC, "r")
682 json_answer = str('{ "static": [')
683 json_answer += str(json_me(config,"static"))
684 json_answer += str('],')
685 json_answer += str('"dynamic": [')
687 config = open(DYNAMIC, "r")
688 json_answer += str(json_me(config,"dynamic"))
689 json_answer += str('],')
690 json_answer += str('"animation": [')
692 config = open(ANIMATION, "r")
693 json_answer += str(json_me(config,"animation"))
694 json_answer += str('] }')
698 return HttpResponse (json_answer, mimetype="application/json")
700 def pres_view_animation(request, constraints, id):
702 # sites crees depuis 2008
703 # static.py?contraints=']date_created':1262325600&id='name_id"'
705 # method = request.getvalue('method') #ex : GetSites
706 #constraints = "']date_created':1262325600"
712 # method = 'GetSites'#request.getvalue('method') #ex : GetSites
713 # constraints = {}#request.getvalue('constraints') // nul = {}
714 # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
716 config_file = open(ANIMATION, "r")
717 for ligne in config_file:
718 if not ligne.startswith('#'):
719 ligne = ligne.split('\n')
720 first = ligne[0].split(';')
721 if (str(first[1]) == str(id)):
725 #Les print_method, print_option sont definis par le client (js)
726 #Les animations acceptent que les connexions anonymous
727 # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
728 args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
731 #Creation d'un objet event
735 "print_options": event.print_options,
736 "print_method": event.print_method,
737 "message": event.data
742 json_answer = json.dumps(cmd)
743 return HttpResponse (json_answer, mimetype="application/json")
745 def pres_view_static(request, constraints, id):
746 #constraints = "']date_created':1262325600"
749 # method = 'GetSites'#request.getvalue('method') #ex : GetSites
750 # constraints = {}#request.getvalue('constraints') // nul = {}
751 # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
753 config_file = open(STATIC, "r")
754 for ligne in config_file:
755 if not ligne.startswith('#'):
756 ligne = ligne.split('\n')
757 first = ligne[0].split(';')
758 if (str(first[1]) == str(id)):
762 #Les print_method, print_option sont definis par le client (js)
763 #Les animations acceptent que les connexions anonymous
764 # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
765 args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
768 #Creation d'un objet event
772 "print_options": event.print_options,
773 "print_method": event.print_method,
774 "message": event.data
779 json_answer = json.dumps(cmd)
780 return HttpResponse (json_answer, mimetype="application/json")
782 class ValidatePendingView(TemplateView):
783 template_name = "validate_pending.html"
785 def get_context_data(self, **kwargs):
786 # We might have slices on different registries with different user accounts
787 # 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
788 # Different registries mean different identities, unless we identify via SFA HRN or have associated the user email to a single hrn
790 #messages.info(self.request, 'You have logged in')
791 page = Page(self.request)
793 ctx_my_authorities = {}
794 ctx_delegation_authorities = {}
797 # The user need to be logged in
798 if the_user(self.request):
799 # Who can a PI validate:
800 # His own authorities + those he has credentials for.
801 # In MySlice we need to look at credentials also.
804 # XXX This will have to be asynchroneous. Need to implement barriers,
805 # for now it will be sufficient to have it working statically
807 # get user_id to later on query accounts
808 # XXX Having real query plan on local tables would simplify all this
809 # XXX $user_email is still not available for local tables
810 #user_query = Query().get('local:user').filter_by('email', '==', '$user_email').select('user_id')
811 user_query = Query().get('local:user').filter_by('email', '==', the_user(self.request)).select('user_id')
812 user, = execute_query(self.request, user_query)
813 user_id = user['user_id']
815 # Query manifold to learn about available SFA platforms for more information
816 # In general we will at least have the portal
817 # For now we are considering all registries
820 sfa_platforms_query = Query().get('local:platform').filter_by('gateway_type', '==', 'sfa').select('platform_id', 'platform', 'auth_type')
821 sfa_platforms = execute_query(self.request, sfa_platforms_query)
822 for sfa_platform in sfa_platforms:
823 print "SFA PLATFORM > ", sfa_platform['platform']
824 if not 'auth_type' in sfa_platform:
826 auth = sfa_platform['auth_type']
827 if not auth in all_authorities:
828 all_authorities.append(auth)
829 platform_ids.append(sfa_platform['platform_id'])
831 # We can check on which the user has authoritity credentials = PI rights
832 credential_authorities = set()
833 credential_authorities_expired = set()
835 # User account on these registries
836 user_accounts_query = Query.get('local:account').filter_by('user_id', '==', user_id).filter_by('platform_id', 'included', platform_ids).select('config')
837 user_accounts = execute_query(self.request, user_accounts_query)
841 for user_account in user_accounts:
842 config = json.loads(user_account['config'])
844 if 'authority_credentials' in config:
845 for authority_hrn, credential in config['authority_credentials'].items():
846 #if credential is not expired:
847 credential_authorities.add(authority_hrn)
849 # credential_authorities_expired.add(authority_hrn)
850 if 'delegated_authority_credentials' in config:
851 for authority_hrn, credential in config['delegated_authority_credentials'].items():
852 #if credential is not expired:
853 credential_authorities.add(authority_hrn)
855 # credential_authorities_expired.add(authority_hrn)
857 print 'credential_authorities =', credential_authorities
858 print 'credential_authorities_expired =', credential_authorities_expired
860 # ** Where am I a PI **
861 # For this we need to ask SFA (of all authorities) = PI function
862 pi_authorities_query = Query.get('user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
863 pi_authorities_tmp = execute_query(self.request, pi_authorities_query)
864 pi_authorities = set()
865 for pa in pi_authorities_tmp:
866 pi_authorities |= set(pa['pi_authorities'])
868 print "pi_authorities =", pi_authorities
870 # My authorities + I have a credential
871 pi_credential_authorities = pi_authorities & credential_authorities
872 pi_no_credential_authorities = pi_authorities - credential_authorities - credential_authorities_expired
873 pi_expired_credential_authorities = pi_authorities & credential_authorities_expired
874 # Authorities I've been delegated PI rights
875 pi_delegation_credential_authorities = credential_authorities - pi_authorities
876 pi_delegation_expired_authorities = credential_authorities_expired - pi_authorities
878 print "pi_credential_authorities =", pi_credential_authorities
879 print "pi_no_credential_authorities =", pi_no_credential_authorities
880 print "pi_expired_credential_authorities =", pi_expired_credential_authorities
881 print "pi_delegation_credential_authorities = ", pi_delegation_credential_authorities
882 print "pi_delegation_expired_authorities = ", pi_delegation_expired_authorities
884 # Summary intermediary
885 pi_my_authorities = pi_credential_authorities | pi_no_credential_authorities | pi_expired_credential_authorities
886 pi_delegation_authorities = pi_delegation_credential_authorities | pi_delegation_expired_authorities
889 print "pi_my_authorities = ", pi_my_authorities
890 print "pi_delegation_authorities = ", pi_delegation_authorities
893 queried_pending_authorities = pi_my_authorities | pi_delegation_authorities
895 print "queried_pending_authorities = ", queried_pending_authorities
897 requests = get_request_by_authority(queried_pending_authorities)
898 for request in requests:
899 auth_hrn = request['authority_hrn']
901 if auth_hrn in pi_my_authorities:
902 dest = ctx_my_authorities
904 # define the css class
905 if auth_hrn in pi_credential_authorities:
906 request['allowed'] = 'allowed'
907 elif auth_hrn in pi_expired_credential_authorities:
908 request['allowed'] = 'expired'
909 else: # pi_no_credential_authorities
910 request['allowed'] = 'denied'
912 elif auth_hrn in pi_delegation_authorities:
913 dest = ctx_delegation_authorities
915 if auth_hrn in pi_delegation_credential_authorities:
916 request['allowed'] = 'allowed'
917 else: # pi_delegation_expired_authorities
918 request['allowed'] = 'expired'
923 if not auth_hrn in dest:
925 dest[auth_hrn].append(request)
927 context = super(ValidatePendingView, self).get_context_data(**kwargs)
928 context['my_authorities'] = ctx_my_authorities
929 context['delegation_authorities'] = ctx_delegation_authorities
931 # XXX This is repeated in all pages
932 # more general variables expected in the template
933 context['title'] = 'Test view that combines various plugins'
934 # the menu items on the top
935 context['topmenu_items'] = topmenu_items('Dashboard', self.request)
936 # so we can sho who is logged
937 context['username'] = the_user(self.request)
939 # XXX We need to prepare the page for queries
940 #context.update(page.prelude_env())