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
31 from plugins.lists.simplelist import SimpleList
33 from plugins.pres_view import PresView
34 from portal.event import Event
37 from portal import signals
38 from portal.forms import UserRegisterForm, SliceRequestForm, ContactForm
39 from portal.util import RegistrationView, ActivationView
40 from portal.models import PendingUser, PendingSlice
41 from manifold.core.query import Query
42 from manifold.manifoldapi import execute_query
43 from unfold.page import Page
44 from myslice.viewutils import topmenu_items, the_user
45 from django.http import HttpResponseRedirect, HttpResponse
47 from M2Crypto import Rand, RSA, BIO
50 class DashboardView(TemplateView):
51 template_name = "dashboard.html"
53 def get_context_data(self, **kwargs):
54 # We might have slices on different registries with different user accounts
55 # 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
56 # Different registries mean different identities, unless we identify via SFA HRN or have associated the user email to a single hrn
58 #messages.info(self.request, 'You have logged in')
59 page = Page(self.request)
62 #slice_query = Query().get('slice').filter_by('user.user_hrn', 'contains', user_hrn).select('slice_hrn')
63 slice_query = Query().get('user').filter_by('user_hrn', '==', '$user_hrn').select('user_hrn', 'slice.slice_hrn')
64 auth_query = Query().get('network').select('network_hrn')
65 print "AUTH QUERY =====================", auth_query
66 print "filter", auth_query.filters
67 page.enqueue_query(slice_query)
68 page.enqueue_query(auth_query)
70 page.expose_js_metadata()
73 slicelist = SimpleList(
76 key = 'slice.slice_hrn',
80 authlist = SimpleList(
87 context = super(DashboardView, self).get_context_data(**kwargs)
88 context['person'] = self.request.user
89 context['networks'] = authlist.render(self.request)
90 context['slices'] = slicelist.render(self.request)
92 # XXX This is repeated in all pages
93 # more general variables expected in the template
94 context['title'] = 'Test view that combines various plugins'
95 # the menu items on the top
96 context['topmenu_items'] = topmenu_items('Dashboard', self.request)
97 # so we can sho who is logged
98 context['username'] = the_user(self.request)
100 context.update(page.prelude_env())
104 class UserRegisterView(RegistrationView):
106 A registration backend which follows a simple workflow:
108 1. User signs up, inactive account is created.
110 2. Email is sent to user with activation link.
112 3. User clicks activation link, account is now active.
114 Using this backend requires that
116 * ``registration`` be listed in the ``INSTALLED_APPS`` setting
117 (since this backend makes use of models defined in this
120 * The setting ``ACCOUNT_ACTIVATION_DAYS`` be supplied, specifying
121 (as an integer) the number of days from registration during
122 which a user may activate their account (after that period
123 expires, activation will be disallowed).
125 * The creation of the templates
126 ``registration/activation_email_subject.txt`` and
127 ``registration/activation_email.txt``, which will be used for
128 the activation email. See the notes for this backends
129 ``register`` method for details regarding these templates.
131 Additionally, registration can be temporarily closed by adding the
132 setting ``REGISTRATION_OPEN`` and setting it to
133 ``False``. Omitting this setting, or setting it to ``True``, will
134 be interpreted as meaning that registration is currently open and
137 Internally, this is accomplished via storing an activation key in
138 an instance of ``registration.models.RegistrationProfile``. See
139 that model and its custom manager for full documentation of its
140 fields and supported operations.
143 form_class = UserRegisterForm
145 def register(self, request, **cleaned_data):
147 Given a username, email address and password, register a new
148 user account, which will initially be inactive.
150 Along with the new ``User`` object, a new
151 ``registration.models.RegistrationProfile`` will be created,
152 tied to that ``User``, containing the activation key which
153 will be used for this account.
155 An email will be sent to the supplied email address; this
156 email should contain an activation link. The email will be
157 rendered using two templates. See the documentation for
158 ``RegistrationProfile.send_activation_email()`` for
159 information about these templates and the contexts provided to
162 After the ``User`` and ``RegistrationProfile`` are created and
163 the activation email is sent, the signal
164 ``registration.signals.user_registered`` will be sent, with
165 the new ``User`` as the keyword argument ``user`` and the
166 class of this backend as the sender.
169 first_name = cleaned_data['first_name']
170 last_name = cleaned_data['last_name']
171 affiliation= cleaned_data['affiliation']
172 email = cleaned_data['email']
173 password = cleaned_data['password1']
175 #password2 = cleaned_data['password2']
176 keypair = cleaned_data['keypair']
178 #if Site._meta.installed:
179 # site = Site.objects.get_current()
181 # site = RequestSite(request)
184 new_user = PendingUser.objects.create_inactive_user(first_name, last_name, email, password, site)
185 signals.user_registered.send(sender=self.__class__,
190 def get_context_data(self, **kwargs):
191 context = super(UserRegisterView, self).get_context_data(**kwargs)
192 context['topmenu_items'] = topmenu_items('Register', self.request)
193 context['username'] = the_user (self.request)
196 def registration_allowed(self, request):
198 Indicate whether account registration is currently permitted,
199 based on the value of the setting ``REGISTRATION_OPEN``. This
200 is determined as follows:
202 * If ``REGISTRATION_OPEN`` is not specified in settings, or is
203 set to ``True``, registration is permitted.
205 * If ``REGISTRATION_OPEN`` is both specified and set to
206 ``False``, registration is not permitted.
209 return getattr(settings, 'REGISTRATION_OPEN', True)
211 def get_success_url(self, request, user):
213 Return the name of the URL to redirect to after successful
217 return ('user_register_complete', (), {})
220 class UserValidateView(ActivationView):
221 def activate(self, request, activation_key):
223 Given an an activation key, look up and activate the user
224 account corresponding to that key (if possible).
226 After successful activation, the signal
227 ``registration.signals.user_activated`` will be sent, with the
228 newly activated ``User`` as the keyword argument ``user`` and
229 the class of this backend as the sender.
232 activated_user = RegistrationProfile.objects.activate_user(activation_key)
234 signals.user_activated.send(sender=self.__class__,
237 return activated_user
239 def get_success_url(self, request, user):
240 return ('registration_activation_complete', (), {})
243 # DEPRECATED #from portal.portalpage import PortalPage
244 # DEPRECATED #from plugins.wizard import Wizard
245 # DEPRECATED #from plugins.form import CreateForm
246 # DEPRECATED #from plugins.raw.raw import Raw # XXX
248 # DEPRECATED #from myslice.viewutils import the_user
250 # DEPRECATED #from django.template.loader import render_to_string
251 # DEPRECATED #from django.template import RequestContext
252 # DEPRECATED #from django.views import generic
254 # DEPRECATED #from django.contrib.formtools.wizard.views import NamedUrlSessionWizardView
255 # DEPRECATED ##from django.core.files.storage import FileSystemStorage
256 # DEPRECATED #from django.core.files.storage import default_storage
258 # DEPRECATED ##class MerlinWizard(NamedUrlSessionWizardView):
263 # DEPRECATED ## @classonlymethod
264 # DEPRECATED ## def as_view(cls, *args, **kwargs):
265 # DEPRECATED ## kwargs.update({
266 # DEPRECATED ## 'form_list': [
267 # DEPRECATED ## NameForm,
268 # DEPRECATED ## QuestForm,
269 # DEPRECATED ## ColorForm,
271 # DEPRECATED ## 'url_name': 'merlin_wizard'
273 # DEPRECATED ## return super(MerlinWizard, cls).as_view(*args, **kwargs)
275 # DEPRECATED #class UserRegisterWizardView(NamedUrlSessionWizardView):
276 # DEPRECATED ##class UserRegisterWizardView(LoginRequiredMixin, NamedUrlSessionWizardView):
277 # DEPRECATED # # Notice that I specify a file storage instance. If you don't specify this,
278 # DEPRECATED # # and you need to support FileField or ImageField in your forms, you'll get
279 # DEPRECATED # # errors from Django. This is something else I think could be handled by
280 # DEPRECATED # # the views better. Seems to me that it should just use whatever the
281 # DEPRECATED # # default/specified storage is for the rest of your project/application.
282 # DEPRECATED # file_storage = default_storage # FileSystemStorage()
283 # DEPRECATED # template_name = "register_user_wizard.html"
285 # DEPRECATED # def done(self, form_list, **kwargs):
286 # DEPRECATED # step1_form = form_list[0]
287 # DEPRECATED # step2_form = form_list[1]
289 # DEPRECATED # productext = self.create_product(product_form)
290 # DEPRECATED # shippings = self.create_shippings(productext, shipping_forms)
291 # DEPRECATED # images = self.create_images(productext, image_forms)
293 # DEPRECATED # if all([productext, shippings, images]):
294 # DEPRECATED # del self.request.session["wizard_product_wizard_view"]
296 # DEPRECATED # messages.success(self.request,
297 # DEPRECATED # _("Your product has been created."))
298 # DEPRECATED # return HttpResponseRedirect(self.get_success_url(productext))
300 # DEPRECATED # messages.error(self.request, _("Something went wrong creating your "
301 # DEPRECATED # "product. Please try again or contact support."))
302 # DEPRECATED # return HttpResponseRedirect(reverse("register_wizard"))
304 # DEPRECATED # #def get_form_kwargs(self, step):
305 # DEPRECATED # # if step == "product":
306 # DEPRECATED # # return {"user": self.request.user}
307 # DEPRECATED # # return {}
309 # DEPRECATED ## The portal should hook the slice and user creation pages
311 # DEPRECATED #def register_user(request):
313 # DEPRECATED # if request.method == 'POST':
314 # DEPRECATED # form = UserRegisterForm(request.POST) # Nous reprenons les données
315 # DEPRECATED # if form.is_valid():
316 # DEPRECATED # first_name = form.cleaned_data['first_name']
317 # DEPRECATED # last_name = form.cleaned_data['last_name']
318 # DEPRECATED # email = form.cleaned_data['email']
319 # DEPRECATED # password = form.cleaned_data['password']
320 # DEPRECATED # password2 = form.cleaned_data['password2']
321 # DEPRECATED # keypair = form.cleaned_data['keypair']
322 # DEPRECATED # ## Ici nous pouvons traiter les données du formulaire
323 # DEPRECATED # #sujet = form.cleaned_data['sujet']
324 # DEPRECATED # #message = form.cleaned_data['message']
325 # DEPRECATED # #envoyeur = form.cleaned_data['envoyeur']
326 # DEPRECATED # #renvoi = form.cleaned_data['renvoi']
327 # DEPRECATED # ## Nous pourrions ici envoyer l'e-mail grâce aux données que nous venons de récupérer
328 # DEPRECATED # #envoi = True
330 # DEPRECATED # form = UserRegisterForm()
331 # DEPRECATED # return render(request, 'register_user.html', locals())
333 # DEPRECATED #def index(request):
335 # DEPRECATED # WIZARD_TITLE = 'User registration'
336 # DEPRECATED # STEP1_TITLE = 'Enter your details'
337 # DEPRECATED # STEP2_TITLE = 'Select your institution'
338 # DEPRECATED # STEP3_TITLE = 'Authentication'
339 # DEPRECATED # STEP4_TITLE = 'Request a slice (optional)'
340 # DEPRECATED # STEP5_TITLE = 'Waiting for validation'
341 # DEPRECATED # STEP6_TITLE = 'Account validated'
343 # DEPRECATED # STEP0 = render_to_string('account_validated.html', context_instance=RequestContext(request))
344 # DEPRECATED # STEP2_HTML = """
345 # DEPRECATED # coucou
347 # DEPRECATED # STEP4 = """
350 # DEPRECATED # STEP5 = render_to_string('account_validated.html', context_instance=RequestContext(request))
352 # DEPRECATED # p = PortalPage(request)
354 # DEPRECATED # # This is redundant with the Wizard title
355 # DEPRECATED # p << "<h3>User registration</h3>"
357 # DEPRECATED # sons = []
358 # DEPRECATED # start_step = 1
360 # DEPRECATED # # STEP 1
361 # DEPRECATED # # If the user already exists (is logged), let's display a summary of his account details
362 # DEPRECATED # # Otherwise propose a form to fill in
363 # DEPRECATED # if the_user(request):
364 # DEPRECATED # # Fill a disabled form with user info
365 # DEPRECATED # # Please logout to register another user
366 # DEPRECATED # sons.append(Raw(page=p, title=STEP1_TITLE, togglable=False, html=STEP0))
367 # DEPRECATED # start_step += 1
369 # DEPRECATED # # We could pass a list of fields also, instead of retrieving them from metadata
370 # DEPRECATED # # Otherwise we need some heuristics to display nice forms
371 # DEPRECATED # # XXX Could we log the user in after the form is validated ?
372 # DEPRECATED # # XXX Explain the password is for XXX
373 # DEPRECATED # field_list = [{
374 # DEPRECATED # 'name' : 'First name',
375 # DEPRECATED # 'field' : 'firstname',
376 # DEPRECATED # 'type' : 'text',
377 # DEPRECATED # 'validate_rx' : '^[a-zA-Z -]+$',
378 # DEPRECATED # 'validate_err': 'Your first name must be comprised of letters only',
379 # DEPRECATED # 'description' : 'Enter your first name',
381 # DEPRECATED # 'name' : 'Last name',
382 # DEPRECATED # 'field' : 'lastname',
383 # DEPRECATED # 'type' : 'text',
384 # DEPRECATED # 'validate_rx' : '^[a-zA-Z -]+$',
385 # DEPRECATED # 'validate_err': 'Your last name must be comprised of letters only',
386 # DEPRECATED # 'description' : 'Enter your last name',
388 # DEPRECATED # 'name' : 'Email',
389 # DEPRECATED # 'field' : 'email',
390 # DEPRECATED # 'type' : 'text',
391 # DEPRECATED # 'description' : 'Enter your email address',
393 # DEPRECATED # 'name' : 'Password',
394 # DEPRECATED # 'field' : 'password',
395 # DEPRECATED # 'type' : 'password',
396 # DEPRECATED # 'description' : 'Enter your password',
398 # DEPRECATED # 'name' : 'Confirm password',
399 # DEPRECATED # 'field' : 'password2',
400 # DEPRECATED # 'type' : 'password',
401 # DEPRECATED # 'description' : 'Enter your password again',
403 # DEPRECATED # sons.append(CreateForm(page = p, title = STEP1_TITLE, togglable = False, object = 'local:user', fields = field_list))
405 # DEPRECATED # # STEP 2
406 # DEPRECATED # # If the user already exists (is logged), let's display a summary of its institution
407 # DEPRECATED # # Otherwise propose a form to fill in (we should base our selection on the email)
408 # DEPRECATED # if the_user(request):
409 # DEPRECATED # # Fill a disabled form with institution
410 # DEPRECATED # # Please logout to register another user
411 # DEPRECATED # sons.append(Raw(page=p, title=STEP2_TITLE, togglable=False, html="User created"))
412 # DEPRECATED # start_step += 1
414 # DEPRECATED # sons.append(CreateForm(page = p, title = STEP2_TITLE, togglable = False, object = 'slice')) #institution'))
416 # DEPRECATED # # STEP3
417 # DEPRECATED # # Please should your prefered authentication method
418 # DEPRECATED # # This step should allow the user to either choose the user or managed mode in MySlice
419 # DEPRECATED # sons.append(Raw(page = p, title = STEP3_TITLE, togglable = False, html = STEP2_HTML))
421 # DEPRECATED # # Step 4: Request a slice (optional)
422 # DEPRECATED # sons.append(CreateForm(page = p, title = STEP4_TITLE, togglable = False, object = 'slice'))
424 # DEPRECATED # # Step 5: Your request is waiting for validation
425 # DEPRECATED # # Periodic refresh
426 # DEPRECATED # sons.append(Raw(page = p, title = STEP5_TITLE, togglable = False, html = STEP4))
428 # DEPRECATED # # Step 6: Account validation = welcome for newly validated users
429 # DEPRECATED # # . delegation
430 # DEPRECATED # # . platforms
431 # DEPRECATED # # . slice
432 # DEPRECATED # # . pointers
433 # DEPRECATED # sons.append(Raw(page = p, title = STEP6_TITLE, togglable = False, html = STEP5))
435 # DEPRECATED # wizard = Wizard(
436 # DEPRECATED # page = p,
437 # DEPRECATED # title = WIZARD_TITLE,
438 # DEPRECATED # togglable = False,
439 # DEPRECATED # sons = sons,
440 # DEPRECATED # start_step = start_step,
443 # DEPRECATED # p << wizard.render(request) # in portal page if possible
445 # DEPRECATED # return p.render()
448 # DEPRECATED ## view for my_account
449 # DEPRECATED # class MyAccountView(TemplateView):
450 # DEPRECATED # template_name = "my_account.html"
452 # DEPRECATED # def from_process(self, request, **cleaned_data):
453 # DEPRECATED # #if request.method == 'POST':
454 # DEPRECATED # # if request.POST['submit_name']:
455 # DEPRECATED # if 'fname' in request.POST:
456 # DEPRECATED # messsag= "Got Name"
457 # DEPRECATED # #return render(request, 'portal/my_account.html')
458 # DEPRECATED # #response = HttpResponse("Here's the text of the Web page.")
459 # DEPRECATED # return HttpResponse(message)
461 # DEPRECATED # def get_context_data(self, **kwargs):
462 # DEPRECATED # page = Page(self.request)
463 # DEPRECATED # context = super(MyAccountView, self).get_context_data(**kwargs)
464 # DEPRECATED # context['person'] = self.request.user
465 # DEPRECATED # # XXX This is repeated in all pages
466 # DEPRECATED # # more general variables expected in the template
467 # DEPRECATED # context['title'] = 'User Profile Page'
468 # DEPRECATED # # the menu items on the top
469 # DEPRECATED # context['topmenu_items'] = topmenu_items('my_account', self.request)
470 # DEPRECATED # # so we can sho who is logged
471 # DEPRECATED # context['username'] = the_user(self.request)
472 # DEPRECATED # context.update(page.prelude_env())
473 # DEPRECATED # return context
477 # View for my_account form
478 def my_account(request):
479 return render(request, 'my_account.html', {
481 'topmenu_items': topmenu_items('My Account', request),
482 'username': the_user (request)
486 #my_acc form value processing
487 def acc_process(request):
488 # getting the user_id from the session [now hardcoded]
489 get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
490 if 'submit_name' in request.POST:
491 edited_first_name = request.POST['fname']
492 edited_last_name = request.POST['lname']
493 #email = 'test_email@gmail.com'
494 #password = 'test_pp'
495 #message = 'F_Name: %s L_name: %s dummy_pp: %s' % (first_name, last_name, password)
498 # insert into DB [needed for registration page]
499 #approach borrowed from register view
500 #new_user = PendingUser.objects.create_inactive_user(edited_first_name, edited_last_name, email, password, site)
501 #conventional approach
502 #b = PendingUser(first_name=edited_first_name, last_name=edited_last_name)
505 # select and update [will be used throughout this view]
506 # select the logged in user [for the moment hard coded]
507 #get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
508 # update first and last name
509 get_user.first_name = edited_first_name
510 get_user.last_name = edited_last_name
513 return HttpResponse('Success: Name Updated!!')
514 elif 'submit_pass' in request.POST:
515 edited_password = request.POST['password']
516 # select the logged in user [for the moment hard coded]
517 #get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
519 get_user.password = edited_password
521 return HttpResponse('Success: Password Changed!!')
522 elif 'generate' in request.POST:
524 #from M2Crypto import Rand, RSA, BIO
528 def blank_callback():
529 "Replace the default dashes"
533 Rand.rand_seed (os.urandom (KEY_LENGTH))
535 key = RSA.gen_key (KEY_LENGTH, 65537, blank_callback)
536 # Create memory buffers
537 pri_mem = BIO.MemoryBuffer()
538 pub_mem = BIO.MemoryBuffer()
539 # Save keys to buffers
540 key.save_key_bio(pri_mem, None)
541 key.save_pub_key_bio(pub_mem)
544 public_key = pub_mem.getvalue()
545 private_key = pri_mem.getvalue()
547 keypair = '{"user_public_key":"'+ public_key + '", "user_private_key":"'+ private_key + '"}'
548 keypair = re.sub("\r", "", keypair)
549 keypair = re.sub("\n", "\\n", keypair)
550 #keypair = keypair.rstrip('\r\n')
551 keypair = ''.join(keypair.split())
552 get_user.keypair = keypair
554 return HttpResponse('Success: New Keypair Generated! %s' % keypair)
556 elif 'upload_key' in request.POST:
557 up_file = request.FILES['pubkey']
558 file_content = up_file.read()
559 file_name = up_file.name
560 file_extension = os.path.splitext(file_name)[1]
561 allowed_extension = ['.pub','.txt']
562 if file_extension in allowed_extension and re.search(r'ssh-rsa',file_content):
563 file_content = '{"user_public_key":"'+ file_content +'"}'
564 file_content = re.sub("\r", "", file_content)
565 file_content = re.sub("\n", "\\n",file_content)
566 file_content = ''.join(file_content.split())
567 get_user.keypair = file_content
569 return HttpResponse('Success: Publickey uploaded! Old records overwritten')
571 return HttpResponse('Please upload a valid RSA public key [.txt or .pub].')
574 message = 'You submitted an empty form.'
575 return HttpResponse(message)
577 def register_4m_f4f(request):
578 #return render(request, 'register_4m_f4f.html')
580 #def reg_4m_f4f_process(request):
581 if 'submit' in request.POST:
582 #get_email = PendingUser.objects.get(email)
583 reg_fname = request.POST['firstname']
584 reg_lname = request.POST['lastname']
585 reg_aff = request.POST['affiliation']
586 reg_email = request.POST['email'].lower()
588 #POST value validation
589 if (re.search(r'^[\w+\s.@+-]+$', reg_fname)==None):
590 messages.error(request, 'First Name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
591 #return HttpResponse("Only Letters, Numbers, - and _ allowd in First Name")
592 return render(request, 'register_4m_f4f.html')
593 if (re.search(r'^[\w+\s.@+-]+$', reg_lname) == None):
594 messages.error(request, 'Last Name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
595 #return HttpResponse("Only Letters, Numbers, - and _ is allowed in Last name")
596 return render(request, 'register_4m_f4f.html')
597 if (re.search(r'^[\w+\s.@+-]+$', reg_aff) == None):
598 messages.error(request, 'Affiliation may contain only letters, numbers, spaces and @/./+/-/_ characters.')
599 #return HttpResponse("Only Letters, Numbers and _ is allowed in Affiliation")
600 return render(request, 'register_4m_f4f.html')
601 if PendingUser.objects.filter(email__iexact=reg_email):
602 messages.error(request, 'Email already registered.Please provide a new email address.')
603 #return HttpResponse("Email Already exists")
604 return render(request, 'register_4m_f4f.html')
605 if 'generate' in request.POST['question']:
607 #from M2Crypto import Rand, RSA, BIO
611 def blank_callback():
612 "Replace the default dashes"
616 Rand.rand_seed (os.urandom (KEY_LENGTH))
618 key = RSA.gen_key (KEY_LENGTH, 65537, blank_callback)
619 # Create memory buffers
620 pri_mem = BIO.MemoryBuffer()
621 pub_mem = BIO.MemoryBuffer()
622 # Save keys to buffers
623 key.save_key_bio(pri_mem, None)
624 key.save_pub_key_bio(pub_mem)
626 public_key = pub_mem.getvalue()
627 private_key = pri_mem.getvalue()
629 keypair = '{"user_public_key":"'+ public_key + '", "user_private_key":"'+ private_key + '"}'
630 keypair = re.sub("\r", "", keypair)
631 keypair = re.sub("\n", "\\n", keypair)
632 #keypair = keypair.rstrip('\r\n')
633 keypair = ''.join(keypair.split())
634 #return HttpResponse(keypair)
636 up_file = request.FILES['user_public_key']
637 file_content = up_file.read()
638 file_name = up_file.name
639 file_extension = os.path.splitext(file_name)[1]
640 allowed_extension = ['.pub','.txt']
641 if file_extension in allowed_extension and re.search(r'ssh-rsa',file_content):
642 keypair = '{"user_public_key":"'+ file_content +'"}'
643 keypair = re.sub("\r", "", keypair)
644 keypair = re.sub("\n", "\\n",keypair)
645 keypair = ''.join(keypair.split())
647 return HttpResponse('Please upload a valid RSA public key [.txt or .pub].')
649 b = PendingUser(first_name=reg_fname, last_name=reg_lname, affiliation=reg_aff,
650 email=reg_email, password=request.POST['password'], keypair=keypair)
653 return render(request, 'user_register_complete.html')
654 return render(request, 'register_4m_f4f.html')
657 # view for contact form
658 def contact(request):
659 if request.method == 'POST': # If the form has been submitted...
660 form = ContactForm(request.POST) # A form bound to the POST data
661 if form.is_valid(): # All validation rules pass
662 # Process the data in form.cleaned_data
663 first_name = form.cleaned_data['first_name']
664 last_name = form.cleaned_data['last_name']
665 affiliation = form.cleaned_data['affiliation']
666 subject = form.cleaned_data['subject']
667 message = form.cleaned_data['message']
668 email = form.cleaned_data['email'] # email of the sender
669 cc_myself = form.cleaned_data['cc_myself']
671 recipients = ['yasin.upmc@gmail.com']
673 recipients.append(email)
675 from django.core.mail import send_mail
676 send_mail("Onelab user submitted a query ", [first_name,last_name,affiliation,subject,message], email, recipients)
677 return render(request,'contact_sent.html') # Redirect after POST
679 form = ContactForm() # An unbound form
681 return render(request, 'contact.html', {
683 'topmenu_items': topmenu_items('Contact Us', request),
684 'username': the_user (request)
689 def slice_request(request):
690 if request.method == 'POST': # If the form has been submitted...
691 form = SliceRequestForm(request.POST) # A form bound to the POST data
692 if form.is_valid(): # All validation rules pass
693 # Process the data in form.cleaned_data
694 slice_name = form.cleaned_data['slice_name']
695 number_of_nodes = form.cleaned_data['number_of_nodes']
696 type_of_nodes = form.cleaned_data['type_of_nodes']
697 purpose = form.cleaned_data['purpose']
698 email = form.cleaned_data['email'] # email of the sender
699 cc_myself = form.cleaned_data['cc_myself']
701 recipients = ['yasin.upmc@gmail.com','jordan.auge@lip6.fr']
703 recipients.append(email)
705 from django.core.mail import send_mail
706 send_mail("Onelab New Slice request form submitted", [slice_name,number_of_nodes,type_of_nodes,purpose], email, recipients)
707 return render(request,'slicereq_recvd.html') # Redirect after POST
709 form = SliceRequestForm() # An unbound form
712 # template_env['form'] = form
713 # template_env['topmenu_items'] = topmenu_items('Request a slice', request)
714 # template_env['unfold1_main'] = render(request, 'slice_request_.html', {
717 # from django.shortcuts import render_to_response
718 # from django.template import RequestContext
719 # return render_to_response ('view-unfold1.html',template_env,
720 # context_instance=RequestContext(request))
722 return render(request, 'slice_request.html', {
724 'topmenu_items': topmenu_items('Request a slice', request),
725 'username': the_user (request)
729 class PresViewView(TemplateView):
730 template_name = "view-unfold1.html"
732 def get_context_data(self, **kwargs):
734 page = Page(self.request)
736 pres_view = PresView(page = page)
738 context = super(PresViewView, self).get_context_data(**kwargs)
740 #context['ALL_STATIC'] = "all_static"
741 context['unfold1_main'] = pres_view.render(self.request)
743 # XXX This is repeated in all pages
744 # more general variables expected in the template
745 context['title'] = 'Test view that combines various plugins'
746 # the menu items on the top
747 context['topmenu_items'] = topmenu_items('PresView', self.request)
748 # so we can sho who is logged
749 context['username'] = the_user(self.request)
751 prelude_env = page.prelude_env()
752 context.update(prelude_env)
756 def json_me(config_file,type):
758 for ligne in config_file:
759 if not ligne.startswith('#'):
760 args = ligne.split(';')
761 json_answer += str('{ "name": "' + args[0] + '" ,"id":"' + args[1] + '" ,"descriptif":"' + args[2]+'"')
763 json_answer += str(',"contraints":')
765 json_answer += str('""')
767 json_answer += str(args[3])
768 json_answer += str('},')
769 return json_answer[:-1]
772 DIR = '/var/myslice/'
773 STATIC = '%s/config_method_static' % DIR
774 DYNAMIC = '%s/config_method_dynamic' % DIR
775 ANIMATION = '%s/config_method_animation' % DIR
777 def pres_view_methods(request, type):
781 elif type =="static":
782 config = open(STATIC, "r")
783 json_answer = str('{ "options": [')
784 json_answer += str(json_me(config,"static"))
785 json_answer += str('] }')
787 elif type =="dynamic":
788 config = open(DYNAMIC, "r")
789 json_answer = str('{ "options": [')
790 json_answer += str(json_me(config,"dynamic"))
791 json_answer += str('] }')
793 elif type =="animation":
794 config = open(ANIMATION, "r")
795 json_answer = str('{ "options": [')
796 json_answer += str(json_me(config,"animation"))
797 json_answer += str('] }')
800 config = open(STATIC, "r")
801 json_answer = str('{ "static": [')
802 json_answer += str(json_me(config,"static"))
803 json_answer += str('],')
804 json_answer += str('"dynamic": [')
806 config = open(DYNAMIC, "r")
807 json_answer += str(json_me(config,"dynamic"))
808 json_answer += str('],')
809 json_answer += str('"animation": [')
811 config = open(ANIMATION, "r")
812 json_answer += str(json_me(config,"animation"))
813 json_answer += str('] }')
817 return HttpResponse (json_answer, mimetype="application/json")
819 def pres_view_animation(request, constraints, id):
821 # sites crees depuis 2008
822 # static.py?contraints=']date_created':1262325600&id='name_id"'
824 # method = request.getvalue('method') #ex : GetSites
825 #constraints = "']date_created':1262325600"
831 # method = 'GetSites'#request.getvalue('method') #ex : GetSites
832 # constraints = {}#request.getvalue('constraints') // nul = {}
833 # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
835 config_file = open(ANIMATION, "r")
836 for ligne in config_file:
837 if not ligne.startswith('#'):
838 ligne = ligne.split('\n')
839 first = ligne[0].split(';')
840 if (str(first[1]) == str(id)):
844 #Les print_method, print_option sont definis par le client (js)
845 #Les animations acceptent que les connexions anonymous
846 # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
847 args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
850 #Creation d'un objet event
854 "print_options": event.print_options,
855 "print_method": event.print_method,
856 "message": event.data
861 json_answer = json.dumps(cmd)
862 return HttpResponse (json_answer, mimetype="application/json")
864 def pres_view_static(request, constraints, id):
865 #constraints = "']date_created':1262325600"
868 # method = 'GetSites'#request.getvalue('method') #ex : GetSites
869 # constraints = {}#request.getvalue('constraints') // nul = {}
870 # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
872 config_file = open(STATIC, "r")
873 for ligne in config_file:
874 if not ligne.startswith('#'):
875 ligne = ligne.split('\n')
876 first = ligne[0].split(';')
877 if (str(first[1]) == str(id)):
881 #Les print_method, print_option sont definis par le client (js)
882 #Les animations acceptent que les connexions anonymous
883 # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
884 args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
887 #Creation d'un objet event
891 "print_options": event.print_options,
892 "print_method": event.print_method,
893 "message": event.data
898 json_answer = json.dumps(cmd)
899 return HttpResponse (json_answer, mimetype="application/json")
901 class ValidatePendingView(TemplateView):
902 template_name = "validate_pending.html"
904 def get_context_data(self, **kwargs):
905 # We might have slices on different registries with different user accounts
906 # 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
907 # Different registries mean different identities, unless we identify via SFA HRN or have associated the user email to a single hrn
909 #messages.info(self.request, 'You have logged in')
910 page = Page(self.request)
912 ctx_my_authorities = {}
913 ctx_delegation_authorities = {}
916 # The user need to be logged in
917 if the_user(self.request):
918 # Who can a PI validate:
919 # His own authorities + those he has credentials for.
920 # In MySlice we need to look at credentials also.
923 # XXX This will have to be asynchroneous. Need to implement barriers,
924 # for now it will be sufficient to have it working statically
926 # get user_id to later on query accounts
927 # XXX Having real query plan on local tables would simplify all this
928 # XXX $user_email is still not available for local tables
929 #user_query = Query().get('local:user').filter_by('email', '==', '$user_email').select('user_id')
930 user_query = Query().get('local:user').filter_by('email', '==', the_user(self.request)).select('user_id')
931 user, = execute_query(self.request, user_query)
932 user_id = user['user_id']
934 # Query manifold to learn about available SFA platforms for more information
935 # In general we will at least have the portal
936 # For now we are considering all registries
939 sfa_platforms_query = Query().get('local:platform').filter_by('gateway_type', '==', 'sfa').select('platform_id', 'platform', 'auth_type')
940 sfa_platforms = execute_query(self.request, sfa_platforms_query)
941 for sfa_platform in sfa_platforms:
942 print "SFA PLATFORM > ", sfa_platform['platform']
943 if not 'auth_type' in sfa_platform:
945 auth = sfa_platform['auth_type']
946 if not auth in all_authorities:
947 all_authorities.append(auth)
948 platform_ids.append(sfa_platform['platform_id'])
950 # We can check on which the user has authoritity credentials = PI rights
951 credential_authorities = set()
952 credential_authorities_expired = set()
954 # User account on these registries
955 user_accounts_query = Query.get('local:account').filter_by('user_id', '==', user_id).filter_by('platform_id', 'included', platform_ids).select('config')
956 user_accounts = execute_query(self.request, user_accounts_query)
960 for user_account in user_accounts:
961 config = json.loads(user_account['config'])
963 if 'authority_credentials' in config:
964 for authority_hrn, credential in config['authority_credentials'].items():
965 #if credential is not expired:
966 credential_authorities.add(authority_hrn)
968 # credential_authorities_expired.add(authority_hrn)
969 if 'delegated_authority_credentials' in config:
970 for authority_hrn, credential in config['delegated_authority_credentials'].items():
971 #if credential is not expired:
972 credential_authorities.add(authority_hrn)
974 # credential_authorities_expired.add(authority_hrn)
976 print 'credential_authorities =', credential_authorities
977 print 'credential_authorities_expired =', credential_authorities_expired
979 # ** Where am I a PI **
980 # For this we need to ask SFA (of all authorities) = PI function
981 pi_authorities_query = Query.get('user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
982 pi_authorities_tmp = execute_query(self.request, pi_authorities_query)
983 pi_authorities = set()
984 for pa in pi_authorities_tmp:
985 pi_authorities |= set(pa['pi_authorities'])
987 print "pi_authorities =", pi_authorities
989 # My authorities + I have a credential
990 pi_credential_authorities = pi_authorities & credential_authorities
991 pi_no_credential_authorities = pi_authorities - credential_authorities - credential_authorities_expired
992 pi_expired_credential_authorities = pi_authorities & credential_authorities_expired
993 # Authorities I've been delegated PI rights
994 pi_delegation_credential_authorities = credential_authorities - pi_authorities
995 pi_delegation_expired_authorities = credential_authorities_expired - pi_authorities
997 print "pi_credential_authorities =", pi_credential_authorities
998 print "pi_no_credential_authorities =", pi_no_credential_authorities
999 print "pi_expired_credential_authorities =", pi_expired_credential_authorities
1000 print "pi_delegation_credential_authorities = ", pi_delegation_credential_authorities
1001 print "pi_delegation_expired_authorities = ", pi_delegation_expired_authorities
1003 # Summary intermediary
1004 pi_my_authorities = pi_credential_authorities | pi_no_credential_authorities | pi_expired_credential_authorities
1005 pi_delegation_authorities = pi_delegation_credential_authorities | pi_delegation_expired_authorities
1008 print "pi_my_authorities = ", pi_my_authorities
1009 print "pi_delegation_authorities = ", pi_delegation_authorities
1012 queried_pending_authorities = pi_my_authorities | pi_delegation_authorities
1014 print "queried_pending_authorities = ", queried_pending_authorities
1016 # Pending requests + authorities
1017 #pending_users = PendingUser.objects.filter(authority_hrn__in = queried_pending_authorities).all()
1018 #pending_slices = PendingSlice.objects.filter(authority_hrn__in = queried_pending_authorities).all()
1019 pending_users = PendingUser.objects.all()
1020 pending_slices = PendingSlice.objects.all()
1022 # Dispatch requests and build the proper structure for the template:
1024 print "pending users =", pending_users
1025 print "pending slices =", pending_slices
1027 for user in pending_users:
1028 auth_hrn = user.authority_hrn
1030 auth_hrn = "ple.upmc" # XXX HARDCODED
1033 request['type'] = 'user'
1034 request['id'] = 'TODO' # XXX in DB ?
1035 request['timestamp'] = 'TODO' # XXX in DB ?
1036 request['details'] = "%s %s <%s>" % (user.first_name, user.last_name, user.email)
1038 if auth_hrn in pi_my_authorities:
1039 dest = ctx_my_authorities
1041 # define the css class
1042 if auth_hrn in pi_credential_authorities:
1043 request['allowed'] = 'allowed'
1044 elif auth_hrn in pi_expired_credential_authorities:
1045 request['allowed'] = 'expired'
1046 else: # pi_no_credential_authorities
1047 request['allowed'] = 'denied'
1049 elif auth_hrn in pi_delegation_authorities:
1050 dest = ctx_delegation_authorities
1052 if auth_hrn in pi_delegation_credential_authorities:
1053 request['allowed'] = 'allowed'
1054 else: # pi_delegation_expired_authorities
1055 request['allowed'] = 'expired'
1060 if not auth_hrn in dest:
1062 print "auth_hrn [%s] was added %r" % (auth_hrn, request)
1063 dest[auth_hrn].append(request)
1065 for slice in pending_slices:
1066 auth_hrn = slice.authority_hrn
1068 auth_hrn = "ple.upmc" # XXX HARDCODED
1071 request['type'] = 'slice'
1072 request['id'] = 'TODO' # XXX in DB ?
1073 request['timestamp'] = 'TODO' # XXX in DB ?
1074 request['details'] = "Number of nodes: %d -- Type of nodes: %s<br/>%s" % ('TODO', 'TODO', 'TODO') # XXX
1075 if auth_hrn in pi_my_authorities:
1076 dest = ctx_my_authorities
1078 # define the css class
1079 if auth_hrn in pi_credential_authorities:
1080 request['allowed'] = 'allowed'
1081 elif auth_hrn in pi_expired_credential_authorities:
1082 request['allowed'] = 'expired'
1083 else: # pi_no_credential_authorities
1084 request['allowed'] = 'denied'
1086 elif auth_hrn in pi_delegation_authorities:
1087 dest = ctx_delegation_authorities
1089 if auth_hrn in pi_delegation_credential_authorities:
1090 request['allowed'] = 'allowed'
1091 else: # pi_delegation_expired_authorities
1092 request['allowed'] = 'expired'
1094 if not auth_hrn in dest:
1096 dest[auth_hrn].append(request)
1098 context = super(ValidatePendingView, self).get_context_data(**kwargs)
1099 context['my_authorities'] = ctx_my_authorities
1100 context['delegation_authorities'] = ctx_delegation_authorities
1102 # XXX This is repeated in all pages
1103 # more general variables expected in the template
1104 context['title'] = 'Test view that combines various plugins'
1105 # the menu items on the top
1106 context['topmenu_items'] = topmenu_items('Dashboard', self.request)
1107 # so we can sho who is logged
1108 context['username'] = the_user(self.request)
1110 # XXX We need to prepare the page for queries
1111 #context.update(page.prelude_env())