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.utils.decorators import method_decorator
31 from django.contrib.auth.decorators import login_required
33 from plugins.lists.simplelist import SimpleList
34 from plugins.hazelnut import Hazelnut
35 from plugins.pres_view import PresView
36 from portal.event import Event
39 from portal import signals
40 from portal.forms import SliceRequestForm, ContactForm
41 from portal.util import RegistrationView, ActivationView
42 from portal.models import PendingUser, PendingSlice
43 from manifold.core.query import Query
44 from manifold.manifoldapi import execute_query
45 from unfold.page import Page
46 from myslice.viewutils import topmenu_items, the_user
47 from django.http import HttpResponseRedirect, HttpResponse
49 from M2Crypto import Rand, RSA, BIO
52 class DashboardView(TemplateView):
53 template_name = "dashboard.html"
55 #This view requires login
56 @method_decorator(login_required)
57 def dispatch(self, *args, **kwargs):
58 return super(DashboardView, self).dispatch(*args, **kwargs)
60 def get_context_data(self, **kwargs):
61 # We might have slices on different registries with different user accounts
62 # 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
63 # Different registries mean different identities, unless we identify via SFA HRN or have associated the user email to a single hrn
65 #messages.info(self.request, 'You have logged in')
66 page = Page(self.request)
69 #slice_query = Query().get('slice').filter_by('user.user_hrn', 'contains', user_hrn).select('slice_hrn')
70 slice_query = Query().get('user').filter_by('user_hrn', '==', '$user_hrn').select('user_hrn', 'slice.slice_hrn')
71 auth_query = Query().get('network').select('network_hrn')
72 print "AUTH QUERY =====================", auth_query
73 print "filter", auth_query.filters
74 page.enqueue_query(slice_query)
75 page.enqueue_query(auth_query)
77 page.expose_js_metadata()
80 slicelist = SimpleList(
83 key = 'slice.slice_hrn',
87 authlist = SimpleList(
94 context = super(DashboardView, self).get_context_data(**kwargs)
95 context['person'] = self.request.user
96 context['networks'] = authlist.render(self.request)
97 context['slices'] = slicelist.render(self.request)
99 # XXX This is repeated in all pages
100 # more general variables expected in the template
101 context['title'] = 'Test view that combines various plugins'
102 # the menu items on the top
103 context['topmenu_items'] = topmenu_items('Dashboard', self.request)
104 # so we can sho who is logged
105 context['username'] = the_user(self.request)
107 context.update(page.prelude_env())
111 # DEPRECATED #class UserRegisterView(RegistrationView):
113 # DEPRECATED # A registration backend which follows a simple workflow:
115 # DEPRECATED # 1. User signs up, inactive account is created.
117 # DEPRECATED # 2. Email is sent to user with activation link.
119 # DEPRECATED # 3. User clicks activation link, account is now active.
121 # DEPRECATED # Using this backend requires that
123 # DEPRECATED # * ``registration`` be listed in the ``INSTALLED_APPS`` setting
124 # DEPRECATED # (since this backend makes use of models defined in this
125 # DEPRECATED # application).
127 # DEPRECATED # * The setting ``ACCOUNT_ACTIVATION_DAYS`` be supplied, specifying
128 # DEPRECATED # (as an integer) the number of days from registration during
129 # DEPRECATED # which a user may activate their account (after that period
130 # DEPRECATED # expires, activation will be disallowed).
132 # DEPRECATED # * The creation of the templates
133 # DEPRECATED # ``registration/activation_email_subject.txt`` and
134 # DEPRECATED # ``registration/activation_email.txt``, which will be used for
135 # DEPRECATED # the activation email. See the notes for this backends
136 # DEPRECATED # ``register`` method for details regarding these templates.
138 # DEPRECATED # Additionally, registration can be temporarily closed by adding the
139 # DEPRECATED # setting ``REGISTRATION_OPEN`` and setting it to
140 # DEPRECATED # ``False``. Omitting this setting, or setting it to ``True``, will
141 # DEPRECATED # be interpreted as meaning that registration is currently open and
142 # DEPRECATED # permitt ed.
144 # DEPRECATED # Internally, this is accomplished via storing an activation key in
145 # DEPRECATED # an instance of ``registration.models.RegistrationProfile``. See
146 # DEPRECATED # that model and its custom manager for full documentation of its
147 # DEPRECATED # fields and supported operations.
150 # DEPRECATED ## DEPRECATED # form_class = UserRegisterForm
152 # DEPRECATED # def register(self, request, **cleaned_data):
154 # DEPRECATED # Given a username, email address and password, register a new
155 # DEPRECATED # user account, which will initially be inactive.
157 # DEPRECATED # Along with the new ``User`` object, a new
158 # DEPRECATED # ``registration.models.RegistrationProfile`` will be created,
159 # DEPRECATED # tied to that ``User``, containing the activation key which
160 # DEPRECATED # will be used for this account.
162 # DEPRECATED # An email will be sent to the supplied email address; this
163 # DEPRECATED # email should contain an activation link. The email will be
164 # DEPRECATED # rendered using two templates. See the documentation for
165 # DEPRECATED # ``RegistrationProfile.send_activation_email()`` for
166 # DEPRECATED # information about these templates and the contexts provided to
169 # DEPRECATED # After the ``User`` and ``RegistrationProfile`` are created and
170 # DEPRECATED # the activation email is sent, the signal
171 # DEPRECATED # ``registration.signals.user_registered`` will be sent, with
172 # DEPRECATED # the new ``User`` as the keyword argument ``user`` and the
173 # DEPRECATED # class of this backend as the sender.
176 # DEPRECATED # first_name = cleaned_data['first_name']
177 # DEPRECATED # last_name = cleaned_data['last_name']
178 # DEPRECATED # affiliation= cleaned_data['affiliation']
179 # DEPRECATED # email = cleaned_data['email']
180 # DEPRECATED # password = cleaned_data['password1']
182 # DEPRECATED # #password2 = cleaned_data['password2']
183 # DEPRECATED # keypair = cleaned_data['keypair']
185 # DEPRECATED # #if Site._meta.installed:
186 # DEPRECATED # # site = Site.objects.get_current()
187 # DEPRECATED # #else:
188 # DEPRECATED # # site = RequestSite(request)
189 # DEPRECATED # site = None
191 # DEPRECATED # new_user = PendingUser.objects.create_inactive_user(first_name, last_name, email, password, site)
192 # DEPRECATED # signals.user_registered.send(sender=self.__class__,
193 # DEPRECATED # user=new_user,
194 # DEPRECATED # request=request)
195 # DEPRECATED # return new_user
197 # DEPRECATED # def get_context_data(self, **kwargs):
198 # DEPRECATED # context = super(UserRegisterView, self).get_context_data(**kwargs)
199 # DEPRECATED # context['topmenu_items'] = topmenu_items('Register', self.request)
200 # DEPRECATED # context['username'] = the_user (self.request)
201 # DEPRECATED # return context
203 # DEPRECATED # def registration_allowed(self, request):
205 # DEPRECATED # Indicate whether account registration is currently permitted,
206 # DEPRECATED # based on the value of the setting ``REGISTRATION_OPEN``. This
207 # DEPRECATED # is determined as follows:
209 # DEPRECATED # * If ``REGISTRATION_OPEN`` is not specified in settings, or is
210 # DEPRECATED # set to ``True``, registration is permitted.
212 # DEPRECATED # * If ``REGISTRATION_OPEN`` is both specified and set to
213 # DEPRECATED # ``False``, registration is not permitted.
216 # DEPRECATED # return getattr(settings, 'REGISTRATION_OPEN', True)
218 # DEPRECATED # def get_success_url(self, request, user):
220 # DEPRECATED # Return the name of the URL to redirect to after successful
221 # DEPRECATED # user registration.
224 # DEPRECATED # return ('user_register_complete', (), {})
227 # DEPRECATED #class UserValidateView(ActivationView):
228 # DEPRECATED # def activate(self, request, activation_key):
230 # DEPRECATED # Given an an activation key, look up and activate the user
231 # DEPRECATED # account corresponding to that key (if possible).
233 # DEPRECATED # After successful activation, the signal
234 # DEPRECATED # ``registration.signals.user_activated`` will be sent, with the
235 # DEPRECATED # newly activated ``User`` as the keyword argument ``user`` and
236 # DEPRECATED # the class of this backend as the sender.
239 # DEPRECATED # activated_user = RegistrationProfile.objects.activate_user(activation_key)
240 # DEPRECATED # if activated_user:
241 # DEPRECATED # signals.user_activated.send(sender=self.__class__,
242 # DEPRECATED # user=activated_user,
243 # DEPRECATED # request=request)
244 # DEPRECATED # return activated_user
246 # DEPRECATED # def get_success_url(self, request, user):
247 # DEPRECATED # return ('registration_activation_complete', (), {})
250 # DEPRECATED #from portal.portalpage import PortalPage
251 # DEPRECATED #from plugins.wizard import Wizard
252 # DEPRECATED #from plugins.form import CreateForm
253 # DEPRECATED #from plugins.raw.raw import Raw # XXX
255 # DEPRECATED #from myslice.viewutils import the_user
257 # DEPRECATED #from django.template.loader import render_to_string
258 # DEPRECATED #from django.template import RequestContext
259 # DEPRECATED #from django.views import generic
261 # DEPRECATED #from django.contrib.formtools.wizard.views import NamedUrlSessionWizardView
262 # DEPRECATED ##from django.core.files.storage import FileSystemStorage
263 # DEPRECATED #from django.core.files.storage import default_storage
265 # DEPRECATED ##class MerlinWizard(NamedUrlSessionWizardView):
270 # DEPRECATED ## @classonlymethod
271 # DEPRECATED ## def as_view(cls, *args, **kwargs):
272 # DEPRECATED ## kwargs.update({
273 # DEPRECATED ## 'form_list': [
274 # DEPRECATED ## NameForm,
275 # DEPRECATED ## QuestForm,
276 # DEPRECATED ## ColorForm,
278 # DEPRECATED ## 'url_name': 'merlin_wizard'
280 # DEPRECATED ## return super(MerlinWizard, cls).as_view(*args, **kwargs)
282 # DEPRECATED #class UserRegisterWizardView(NamedUrlSessionWizardView):
283 # DEPRECATED ##class UserRegisterWizardView(LoginRequiredMixin, NamedUrlSessionWizardView):
284 # DEPRECATED # # Notice that I specify a file storage instance. If you don't specify this,
285 # DEPRECATED # # and you need to support FileField or ImageField in your forms, you'll get
286 # DEPRECATED # # errors from Django. This is something else I think could be handled by
287 # DEPRECATED # # the views better. Seems to me that it should just use whatever the
288 # DEPRECATED # # default/specified storage is for the rest of your project/application.
289 # DEPRECATED # file_storage = default_storage # FileSystemStorage()
290 # DEPRECATED # template_name = "register_user_wizard.html"
292 # DEPRECATED # def done(self, form_list, **kwargs):
293 # DEPRECATED # step1_form = form_list[0]
294 # DEPRECATED # step2_form = form_list[1]
296 # DEPRECATED # productext = self.create_product(product_form)
297 # DEPRECATED # shippings = self.create_shippings(productext, shipping_forms)
298 # DEPRECATED # images = self.create_images(productext, image_forms)
300 # DEPRECATED # if all([productext, shippings, images]):
301 # DEPRECATED # del self.request.session["wizard_product_wizard_view"]
303 # DEPRECATED # messages.success(self.request,
304 # DEPRECATED # _("Your product has been created."))
305 # DEPRECATED # return HttpResponseRedirect(self.get_success_url(productext))
307 # DEPRECATED # messages.error(self.request, _("Something went wrong creating your "
308 # DEPRECATED # "product. Please try again or contact support."))
309 # DEPRECATED # return HttpResponseRedirect(reverse("register_wizard"))
311 # DEPRECATED # #def get_form_kwargs(self, step):
312 # DEPRECATED # # if step == "product":
313 # DEPRECATED # # return {"user": self.request.user}
314 # DEPRECATED # # return {}
316 # DEPRECATED ## The portal should hook the slice and user creation pages
318 # DEPRECATED #def register_user(request):
320 # DEPRECATED # if request.method == 'POST':
321 # DEPRECATED # form = UserRegisterForm(request.POST) # Nous reprenons les données
322 # DEPRECATED # if form.is_valid():
323 # DEPRECATED # first_name = form.cleaned_data['first_name']
324 # DEPRECATED # last_name = form.cleaned_data['last_name']
325 # DEPRECATED # email = form.cleaned_data['email']
326 # DEPRECATED # password = form.cleaned_data['password']
327 # DEPRECATED # password2 = form.cleaned_data['password2']
328 # DEPRECATED # keypair = form.cleaned_data['keypair']
329 # DEPRECATED # ## Ici nous pouvons traiter les données du formulaire
330 # DEPRECATED # #sujet = form.cleaned_data['sujet']
331 # DEPRECATED # #message = form.cleaned_data['message']
332 # DEPRECATED # #envoyeur = form.cleaned_data['envoyeur']
333 # DEPRECATED # #renvoi = form.cleaned_data['renvoi']
334 # DEPRECATED # ## Nous pourrions ici envoyer l'e-mail grâce aux données que nous venons de récupérer
335 # DEPRECATED # #envoi = True
337 # DEPRECATED # form = UserRegisterForm()
338 # DEPRECATED # return render(request, 'register_user.html', locals())
340 # DEPRECATED #def index(request):
342 # DEPRECATED # WIZARD_TITLE = 'User registration'
343 # DEPRECATED # STEP1_TITLE = 'Enter your details'
344 # DEPRECATED # STEP2_TITLE = 'Select your institution'
345 # DEPRECATED # STEP3_TITLE = 'Authentication'
346 # DEPRECATED # STEP4_TITLE = 'Request a slice (optional)'
347 # DEPRECATED # STEP5_TITLE = 'Waiting for validation'
348 # DEPRECATED # STEP6_TITLE = 'Account validated'
350 # DEPRECATED # STEP0 = render_to_string('account_validated.html', context_instance=RequestContext(request))
351 # DEPRECATED # STEP2_HTML = """
352 # DEPRECATED # coucou
354 # DEPRECATED # STEP4 = """
357 # DEPRECATED # STEP5 = render_to_string('account_validated.html', context_instance=RequestContext(request))
359 # DEPRECATED # p = PortalPage(request)
361 # DEPRECATED # # This is redundant with the Wizard title
362 # DEPRECATED # p << "<h3>User registration</h3>"
364 # DEPRECATED # sons = []
365 # DEPRECATED # start_step = 1
367 # DEPRECATED # # STEP 1
368 # DEPRECATED # # If the user already exists (is logged), let's display a summary of his account details
369 # DEPRECATED # # Otherwise propose a form to fill in
370 # DEPRECATED # if the_user(request):
371 # DEPRECATED # # Fill a disabled form with user info
372 # DEPRECATED # # Please logout to register another user
373 # DEPRECATED # sons.append(Raw(page=p, title=STEP1_TITLE, togglable=False, html=STEP0))
374 # DEPRECATED # start_step += 1
376 # DEPRECATED # # We could pass a list of fields also, instead of retrieving them from metadata
377 # DEPRECATED # # Otherwise we need some heuristics to display nice forms
378 # DEPRECATED # # XXX Could we log the user in after the form is validated ?
379 # DEPRECATED # # XXX Explain the password is for XXX
380 # DEPRECATED # field_list = [{
381 # DEPRECATED # 'name' : 'First name',
382 # DEPRECATED # 'field' : 'firstname',
383 # DEPRECATED # 'type' : 'text',
384 # DEPRECATED # 'validate_rx' : '^[a-zA-Z -]+$',
385 # DEPRECATED # 'validate_err': 'Your first name must be comprised of letters only',
386 # DEPRECATED # 'description' : 'Enter your first name',
388 # DEPRECATED # 'name' : 'Last name',
389 # DEPRECATED # 'field' : 'lastname',
390 # DEPRECATED # 'type' : 'text',
391 # DEPRECATED # 'validate_rx' : '^[a-zA-Z -]+$',
392 # DEPRECATED # 'validate_err': 'Your last name must be comprised of letters only',
393 # DEPRECATED # 'description' : 'Enter your last name',
395 # DEPRECATED # 'name' : 'Email',
396 # DEPRECATED # 'field' : 'email',
397 # DEPRECATED # 'type' : 'text',
398 # DEPRECATED # 'description' : 'Enter your email address',
400 # DEPRECATED # 'name' : 'Password',
401 # DEPRECATED # 'field' : 'password',
402 # DEPRECATED # 'type' : 'password',
403 # DEPRECATED # 'description' : 'Enter your password',
405 # DEPRECATED # 'name' : 'Confirm password',
406 # DEPRECATED # 'field' : 'password2',
407 # DEPRECATED # 'type' : 'password',
408 # DEPRECATED # 'description' : 'Enter your password again',
410 # DEPRECATED # sons.append(CreateForm(page = p, title = STEP1_TITLE, togglable = False, object = 'local:user', fields = field_list))
412 # DEPRECATED # # STEP 2
413 # DEPRECATED # # If the user already exists (is logged), let's display a summary of its institution
414 # DEPRECATED # # Otherwise propose a form to fill in (we should base our selection on the email)
415 # DEPRECATED # if the_user(request):
416 # DEPRECATED # # Fill a disabled form with institution
417 # DEPRECATED # # Please logout to register another user
418 # DEPRECATED # sons.append(Raw(page=p, title=STEP2_TITLE, togglable=False, html="User created"))
419 # DEPRECATED # start_step += 1
421 # DEPRECATED # sons.append(CreateForm(page = p, title = STEP2_TITLE, togglable = False, object = 'slice')) #institution'))
423 # DEPRECATED # # STEP3
424 # DEPRECATED # # Please should your prefered authentication method
425 # DEPRECATED # # This step should allow the user to either choose the user or managed mode in MySlice
426 # DEPRECATED # sons.append(Raw(page = p, title = STEP3_TITLE, togglable = False, html = STEP2_HTML))
428 # DEPRECATED # # Step 4: Request a slice (optional)
429 # DEPRECATED # sons.append(CreateForm(page = p, title = STEP4_TITLE, togglable = False, object = 'slice'))
431 # DEPRECATED # # Step 5: Your request is waiting for validation
432 # DEPRECATED # # Periodic refresh
433 # DEPRECATED # sons.append(Raw(page = p, title = STEP5_TITLE, togglable = False, html = STEP4))
435 # DEPRECATED # # Step 6: Account validation = welcome for newly validated users
436 # DEPRECATED # # . delegation
437 # DEPRECATED # # . platforms
438 # DEPRECATED # # . slice
439 # DEPRECATED # # . pointers
440 # DEPRECATED # sons.append(Raw(page = p, title = STEP6_TITLE, togglable = False, html = STEP5))
442 # DEPRECATED # wizard = Wizard(
443 # DEPRECATED # page = p,
444 # DEPRECATED # title = WIZARD_TITLE,
445 # DEPRECATED # togglable = False,
446 # DEPRECATED # sons = sons,
447 # DEPRECATED # start_step = start_step,
450 # DEPRECATED # p << wizard.render(request) # in portal page if possible
452 # DEPRECATED # return p.render()
455 # DEPRECATED ## view for my_account
456 # DEPRECATED # class MyAccountView(TemplateView):
457 # DEPRECATED # template_name = "my_account.html"
459 # DEPRECATED # def from_process(self, request, **cleaned_data):
460 # DEPRECATED # #if request.method == 'POST':
461 # DEPRECATED # # if request.POST['submit_name']:
462 # DEPRECATED # if 'fname' in request.POST:
463 # DEPRECATED # messsag= "Got Name"
464 # DEPRECATED # #return render(request, 'portal/my_account.html')
465 # DEPRECATED # #response = HttpResponse("Here's the text of the Web page.")
466 # DEPRECATED # return HttpResponse(message)
468 # DEPRECATED # def get_context_data(self, **kwargs):
469 # DEPRECATED # page = Page(self.request)
470 # DEPRECATED # context = super(MyAccountView, self).get_context_data(**kwargs)
471 # DEPRECATED # context['person'] = self.request.user
472 # DEPRECATED # # XXX This is repeated in all pages
473 # DEPRECATED # # more general variables expected in the template
474 # DEPRECATED # context['title'] = 'User Profile Page'
475 # DEPRECATED # # the menu items on the top
476 # DEPRECATED # context['topmenu_items'] = topmenu_items('my_account', self.request)
477 # DEPRECATED # # so we can sho who is logged
478 # DEPRECATED # context['username'] = the_user(self.request)
479 # DEPRECATED # context.update(page.prelude_env())
480 # DEPRECATED # return context
483 class PlatformsView(TemplateView):
484 template_name = "platforms.html"
486 def get_context_data(self, **kwargs):
487 page = Page(self.request)
489 network_query = Query().get('local:platform').filter_by('disabled', '==', '0').select('platform','platform_longname','gateway_type')
490 page.enqueue_query(network_query)
492 page.expose_js_metadata()
493 page.expose_queries()
494 networklist = Hazelnut(
497 domid = 'checkboxes',
498 # this is the query at the core of the slice list
499 query = network_query,
500 query_all = network_query,
502 datatables_options = {
503 # for now we turn off sorting on the checkboxes columns this way
504 # this of course should be automatic in hazelnut
505 'aoColumns' : [None, None, None, None, {'bSortable': False}],
506 'iDisplayLength' : 25,
507 'bLengthChange' : True,
511 # networklist = SimpleList(
515 # query = network_query,
518 context = super(PlatformsView, self).get_context_data(**kwargs)
519 context['person'] = self.request.user
520 context['networks'] = networklist.render(self.request)
522 # XXX This is repeated in all pages
523 # more general variables expected in the template
524 context['title'] = 'Platforms connected to MySlice'
525 # the menu items on the top
526 context['topmenu_items'] = topmenu_items('Platforms', self.request)
527 # so we can sho who is logged
528 context['username'] = the_user(self.request)
530 context.update(page.prelude_env())
536 # View for 1 platform and its details
537 class PlatformView(TemplateView):
538 template_name = "platform.html"
540 def get_context_data(self, **kwargs):
541 page = Page(self.request)
543 for key, value in kwargs.iteritems():
544 print "%s = %s" % (key, value)
545 if key == "platformname":
548 network_query = Query().get('local:platform').filter_by('platform', '==', platformname).select('platform','platform_longname','gateway_type')
549 page.enqueue_query(network_query)
551 page.expose_js_metadata()
552 page.expose_queries()
553 networklist = Hazelnut(
556 domid = 'checkboxes',
557 # this is the query at the core of the slice list
558 query = network_query,
559 query_all = network_query,
561 datatables_options = {
562 # for now we turn off sorting on the checkboxes columns this way
563 # this of course should be automatic in hazelnut
564 'aoColumns' : [None, None, None, None, {'bSortable': False}],
565 'iDisplayLength' : 25,
566 'bLengthChange' : True,
570 # networklist = SimpleList(
574 # query = network_query,
577 context = super(PlatformView, self).get_context_data(**kwargs)
578 context['person'] = self.request.user
579 context['networks'] = networklist.render(self.request)
581 # XXX This is repeated in all pages
582 # more general variables expected in the template
583 context['title'] = 'Platforms connected to MySlice'
584 # the menu items on the top
585 context['topmenu_items'] = topmenu_items('Platforms', self.request)
586 # so we can sho who is logged
587 context['username'] = the_user(self.request)
589 context.update(page.prelude_env())
595 # View for my_account form
596 def my_account(request):
597 return render(request, 'my_account.html', {
599 'topmenu_items': topmenu_items('My Account', request),
600 'username': the_user (request)
605 #my_acc form value processing
606 def acc_process(request):
607 # getting the user_id from the session [now hardcoded]
608 get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
609 if 'submit_name' in request.POST:
610 edited_first_name = request.POST['fname']
611 edited_last_name = request.POST['lname']
612 #email = 'test_email@gmail.com'
613 #password = 'test_pp'
614 #message = 'F_Name: %s L_name: %s dummy_pp: %s' % (first_name, last_name, password)
617 # insert into DB [needed for registration page]
618 #approach borrowed from register view
619 #new_user = PendingUser.objects.create_inactive_user(edited_first_name, edited_last_name, email, password, site)
620 #conventional approach
621 #b = PendingUser(first_name=edited_first_name, last_name=edited_last_name)
624 # select and update [will be used throughout this view]
625 # select the logged in user [for the moment hard coded]
626 #get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
627 # update first and last name
628 get_user.first_name = edited_first_name
629 get_user.last_name = edited_last_name
632 return HttpResponse('Success: Name Updated!!')
633 elif 'submit_pass' in request.POST:
634 edited_password = request.POST['password']
635 # select the logged in user [for the moment hard coded]
636 #get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
638 get_user.password = edited_password
640 return HttpResponse('Success: Password Changed!!')
641 elif 'generate' in request.POST:
643 #from M2Crypto import Rand, RSA, BIO
647 def blank_callback():
648 "Replace the default dashes"
652 Rand.rand_seed (os.urandom (KEY_LENGTH))
654 key = RSA.gen_key (KEY_LENGTH, 65537, blank_callback)
655 # Create memory buffers
656 pri_mem = BIO.MemoryBuffer()
657 pub_mem = BIO.MemoryBuffer()
658 # Save keys to buffers
659 key.save_key_bio(pri_mem, None)
660 key.save_pub_key_bio(pub_mem)
663 public_key = pub_mem.getvalue()
664 private_key = pri_mem.getvalue()
666 keypair = '{"user_public_key":"'+ public_key + '", "user_private_key":"'+ private_key + '"}'
667 keypair = re.sub("\r", "", keypair)
668 keypair = re.sub("\n", "\\n", keypair)
669 #keypair = keypair.rstrip('\r\n')
670 keypair = ''.join(keypair.split())
671 get_user.keypair = keypair
673 return HttpResponse('Success: New Keypair Generated! %s' % keypair)
675 elif 'upload_key' in request.POST:
676 up_file = request.FILES['pubkey']
677 file_content = up_file.read()
678 file_name = up_file.name
679 file_extension = os.path.splitext(file_name)[1]
680 allowed_extension = ['.pub','.txt']
681 if file_extension in allowed_extension and re.search(r'ssh-rsa',file_content):
682 file_content = '{"user_public_key":"'+ file_content +'"}'
683 file_content = re.sub("\r", "", file_content)
684 file_content = re.sub("\n", "\\n",file_content)
685 file_content = ''.join(file_content.split())
686 get_user.keypair = file_content
688 return HttpResponse('Success: Publickey uploaded! Old records overwritten')
690 return HttpResponse('Please upload a valid RSA public key [.txt or .pub].')
693 message = 'You submitted an empty form.'
694 return HttpResponse(message)
696 def register_4m_f4f(request):
699 authorities_query = Query.get('authority').filter_by('authority_hrn', 'included', ['ple.inria', 'ple.upmc']).select('name', 'authority_hrn')
700 #authorities_query = Query.get('authority').select('authority_hrn')
701 authorities = execute_query(request, authorities_query)
703 if request.method == 'POST':
704 #get_email = PendingUser.objects.get(email)
705 reg_fname = request.POST.get('firstname', '')
706 reg_lname = request.POST.get('lastname', '')
707 reg_aff = request.POST.get('affiliation','')
708 reg_auth = request.POST.get('authority_hrn', '')
709 reg_email = request.POST.get('email','').lower()
711 #POST value validation
712 if (re.search(r'^[\w+\s.@+-]+$', reg_fname)==None):
713 errors.append('First Name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
714 #return HttpResponse("Only Letters, Numbers, - and _ allowd in First Name")
715 #return render(request, 'register_4m_f4f.html')
716 if (re.search(r'^[\w+\s.@+-]+$', reg_lname) == None):
717 errors.append('Last Name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
718 #return HttpResponse("Only Letters, Numbers, - and _ is allowed in Last name")
719 #return render(request, 'register_4m_f4f.html')
720 if (re.search(r'^[\w+\s.@+-]+$', reg_aff) == None):
721 errors.append('Affiliation may contain only letters, numbers, spaces and @/./+/-/_ characters.')
722 #return HttpResponse("Only Letters, Numbers and _ is allowed in Affiliation")
723 #return render(request, 'register_4m_f4f.html')
724 # XXX validate authority hrn !!
725 if PendingUser.objects.filter(email__iexact=reg_email):
726 errors.append('Email already registered.Please provide a new email address.')
727 #return HttpResponse("Email Already exists")
728 #return render(request, 'register_4m_f4f.html')
729 if 'generate' in request.POST['question']:
731 #from M2Crypto import Rand, RSA, BIO
735 def blank_callback():
736 "Replace the default dashes"
740 Rand.rand_seed (os.urandom (KEY_LENGTH))
742 key = RSA.gen_key (KEY_LENGTH, 65537, blank_callback)
743 # Create memory buffers
744 pri_mem = BIO.MemoryBuffer()
745 pub_mem = BIO.MemoryBuffer()
746 # Save keys to buffers
747 key.save_key_bio(pri_mem, None)
748 key.save_pub_key_bio(pub_mem)
750 public_key = pub_mem.getvalue()
751 private_key = pri_mem.getvalue()
753 keypair = '{"user_public_key":"'+ public_key + '", "user_private_key":"'+ private_key + '"}'
754 keypair = re.sub("\r", "", keypair)
755 keypair = re.sub("\n", "\\n", keypair)
756 #keypair = keypair.rstrip('\r\n')
757 keypair = ''.join(keypair.split())
758 #return HttpResponse(keypair)
760 up_file = request.FILES['user_public_key']
761 file_content = up_file.read()
762 file_name = up_file.name
763 file_extension = os.path.splitext(file_name)[1]
764 allowed_extension = ['.pub','.txt']
765 if file_extension in allowed_extension and re.search(r'ssh-rsa',file_content):
766 keypair = '{"user_public_key":"'+ file_content +'"}'
767 keypair = re.sub("\r", "", keypair)
768 keypair = re.sub("\n", "\\n",keypair)
769 keypair = ''.join(keypair.split())
771 errors.append('Please upload a valid RSA public key [.txt or .pub].')
773 #b = PendingUser(first_name=reg_fname, last_name=reg_lname, affiliation=reg_aff,
774 # email=reg_email, password=request.POST['password'], keypair=keypair)
777 b = PendingUser(first_name=reg_fname, last_name=reg_lname, affiliation=reg_aff,
778 authority_hrn=reg_auth,
779 email=reg_email, password=request.POST['password'], keypair=keypair)
781 return render(request, 'user_register_complete.html')
783 return render(request, 'register_4m_f4f.html',{
784 'topmenu_items': topmenu_items('Register', request),
786 'firstname': request.POST.get('firstname', ''),
787 'lastname': request.POST.get('lastname', ''),
788 'affiliation': request.POST.get('affiliation', ''),
789 'authority_hrn': request.POST.get('authority_hrn', ''),
790 'email': request.POST.get('email', ''),
791 'password': request.POST.get('password', ''),
792 'authorities': authorities
796 # view for contact form
797 def contact(request):
798 if request.method == 'POST': # If the form has been submitted...
799 form = ContactForm(request.POST) # A form bound to the POST data
800 if form.is_valid(): # All validation rules pass
801 # Process the data in form.cleaned_data
802 first_name = form.cleaned_data['first_name']
803 last_name = form.cleaned_data['last_name']
804 affiliation = form.cleaned_data['affiliation']
805 subject = form.cleaned_data['subject']
806 message = form.cleaned_data['message']
807 email = form.cleaned_data['email'] # email of the sender
808 cc_myself = form.cleaned_data['cc_myself']
810 recipients = ['yasin.upmc@gmail.com']
812 recipients.append(email)
814 from django.core.mail import send_mail
815 send_mail("Onelab user submitted a query ", [first_name,last_name,affiliation,subject,message], email, recipients)
816 return render(request,'contact_sent.html') # Redirect after POST
818 form = ContactForm() # An unbound form
820 return render(request, 'contact.html', {
822 'topmenu_items': topmenu_items('Contact Us', request),
823 'username': the_user (request)
828 def slice_request(request):
829 if request.method == 'POST': # If the form has been submitted...
830 form = SliceRequestForm(request.POST) # A form bound to the POST data
831 if form.is_valid(): # All validation rules pass
832 # Process the data in form.cleaned_data
833 slice_name = form.cleaned_data['slice_name']
834 number_of_nodes = form.cleaned_data['number_of_nodes']
835 type_of_nodes = form.cleaned_data['type_of_nodes']
836 purpose = form.cleaned_data['purpose']
837 email = form.cleaned_data['email'] # email of the sender
838 cc_myself = form.cleaned_data['cc_myself']
840 recipients = ['yasin.upmc@gmail.com','jordan.auge@lip6.fr']
842 recipients.append(email)
844 from django.core.mail import send_mail
845 send_mail("Onelab New Slice request form submitted", [slice_name,number_of_nodes,type_of_nodes,purpose], email, recipients)
846 return render(request,'slicereq_recvd.html') # Redirect after POST
848 form = SliceRequestForm() # An unbound form
851 # template_env['form'] = form
852 # template_env['topmenu_items'] = topmenu_items('Request a slice', request)
853 # template_env['unfold1_main'] = render(request, 'slice_request_.html', {
856 # from django.shortcuts import render_to_response
857 # from django.template import RequestContext
858 # return render_to_response ('view-unfold1.html',template_env,
859 # context_instance=RequestContext(request))
861 return render(request, 'slice_request.html', {
863 'topmenu_items': topmenu_items('Request a slice', request),
864 'username': the_user (request)
868 class PresViewView(TemplateView):
869 template_name = "view-unfold1.html"
871 def get_context_data(self, **kwargs):
873 page = Page(self.request)
875 pres_view = PresView(page = page)
877 context = super(PresViewView, self).get_context_data(**kwargs)
879 #context['ALL_STATIC'] = "all_static"
880 context['unfold1_main'] = pres_view.render(self.request)
882 # XXX This is repeated in all pages
883 # more general variables expected in the template
884 context['title'] = 'Test view that combines various plugins'
885 # the menu items on the top
886 context['topmenu_items'] = topmenu_items('PresView', self.request)
887 # so we can sho who is logged
888 context['username'] = the_user(self.request)
890 prelude_env = page.prelude_env()
891 context.update(prelude_env)
895 def json_me(config_file,type):
897 for ligne in config_file:
898 if not ligne.startswith('#'):
899 args = ligne.split(';')
900 json_answer += str('{ "name": "' + args[0] + '" ,"id":"' + args[1] + '" ,"descriptif":"' + args[2]+'"')
902 json_answer += str(',"contraints":')
904 json_answer += str('""')
906 json_answer += str(args[3])
907 json_answer += str('},')
908 return json_answer[:-1]
911 DIR = '/var/myslice/'
912 STATIC = '%s/config_method_static' % DIR
913 DYNAMIC = '%s/config_method_dynamic' % DIR
914 ANIMATION = '%s/config_method_animation' % DIR
916 def pres_view_methods(request, type):
920 elif type =="static":
921 config = open(STATIC, "r")
922 json_answer = str('{ "options": [')
923 json_answer += str(json_me(config,"static"))
924 json_answer += str('] }')
926 elif type =="dynamic":
927 config = open(DYNAMIC, "r")
928 json_answer = str('{ "options": [')
929 json_answer += str(json_me(config,"dynamic"))
930 json_answer += str('] }')
932 elif type =="animation":
933 config = open(ANIMATION, "r")
934 json_answer = str('{ "options": [')
935 json_answer += str(json_me(config,"animation"))
936 json_answer += str('] }')
939 config = open(STATIC, "r")
940 json_answer = str('{ "static": [')
941 json_answer += str(json_me(config,"static"))
942 json_answer += str('],')
943 json_answer += str('"dynamic": [')
945 config = open(DYNAMIC, "r")
946 json_answer += str(json_me(config,"dynamic"))
947 json_answer += str('],')
948 json_answer += str('"animation": [')
950 config = open(ANIMATION, "r")
951 json_answer += str(json_me(config,"animation"))
952 json_answer += str('] }')
956 return HttpResponse (json_answer, mimetype="application/json")
958 def pres_view_animation(request, constraints, id):
960 # sites crees depuis 2008
961 # static.py?contraints=']date_created':1262325600&id='name_id"'
963 # method = request.getvalue('method') #ex : GetSites
964 #constraints = "']date_created':1262325600"
970 # method = 'GetSites'#request.getvalue('method') #ex : GetSites
971 # constraints = {}#request.getvalue('constraints') // nul = {}
972 # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
974 config_file = open(ANIMATION, "r")
975 for ligne in config_file:
976 if not ligne.startswith('#'):
977 ligne = ligne.split('\n')
978 first = ligne[0].split(';')
979 if (str(first[1]) == str(id)):
983 #Les print_method, print_option sont definis par le client (js)
984 #Les animations acceptent que les connexions anonymous
985 # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
986 args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
989 #Creation d'un objet event
993 "print_options": event.print_options,
994 "print_method": event.print_method,
995 "message": event.data
1000 json_answer = json.dumps(cmd)
1001 return HttpResponse (json_answer, mimetype="application/json")
1003 def pres_view_static(request, constraints, id):
1004 #constraints = "']date_created':1262325600"
1007 # method = 'GetSites'#request.getvalue('method') #ex : GetSites
1008 # constraints = {}#request.getvalue('constraints') // nul = {}
1009 # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
1011 config_file = open(STATIC, "r")
1012 for ligne in config_file:
1013 if not ligne.startswith('#'):
1014 ligne = ligne.split('\n')
1015 first = ligne[0].split(';')
1016 if (str(first[1]) == str(id)):
1020 #Les print_method, print_option sont definis par le client (js)
1021 #Les animations acceptent que les connexions anonymous
1022 # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
1023 args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
1026 #Creation d'un objet event
1030 "print_options": event.print_options,
1031 "print_method": event.print_method,
1032 "message": event.data
1037 json_answer = json.dumps(cmd)
1038 return HttpResponse (json_answer, mimetype="application/json")
1040 class ValidatePendingView(TemplateView):
1041 template_name = "validate_pending.html"
1043 def get_context_data(self, **kwargs):
1044 # We might have slices on different registries with different user accounts
1045 # 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
1046 # Different registries mean different identities, unless we identify via SFA HRN or have associated the user email to a single hrn
1048 #messages.info(self.request, 'You have logged in')
1049 page = Page(self.request)
1051 ctx_my_authorities = {}
1052 ctx_delegation_authorities = {}
1055 # The user need to be logged in
1056 if the_user(self.request):
1057 # Who can a PI validate:
1058 # His own authorities + those he has credentials for.
1059 # In MySlice we need to look at credentials also.
1062 # XXX This will have to be asynchroneous. Need to implement barriers,
1063 # for now it will be sufficient to have it working statically
1065 # get user_id to later on query accounts
1066 # XXX Having real query plan on local tables would simplify all this
1067 # XXX $user_email is still not available for local tables
1068 #user_query = Query().get('local:user').filter_by('email', '==', '$user_email').select('user_id')
1069 user_query = Query().get('local:user').filter_by('email', '==', the_user(self.request)).select('user_id')
1070 user, = execute_query(self.request, user_query)
1071 user_id = user['user_id']
1073 # Query manifold to learn about available SFA platforms for more information
1074 # In general we will at least have the portal
1075 # For now we are considering all registries
1076 all_authorities = []
1078 sfa_platforms_query = Query().get('local:platform').filter_by('gateway_type', '==', 'sfa').select('platform_id', 'platform', 'auth_type')
1079 sfa_platforms = execute_query(self.request, sfa_platforms_query)
1080 for sfa_platform in sfa_platforms:
1081 print "SFA PLATFORM > ", sfa_platform['platform']
1082 if not 'auth_type' in sfa_platform:
1084 auth = sfa_platform['auth_type']
1085 if not auth in all_authorities:
1086 all_authorities.append(auth)
1087 platform_ids.append(sfa_platform['platform_id'])
1089 # We can check on which the user has authoritity credentials = PI rights
1090 credential_authorities = set()
1091 credential_authorities_expired = set()
1093 # User account on these registries
1094 user_accounts_query = Query.get('local:account').filter_by('user_id', '==', user_id).filter_by('platform_id', 'included', platform_ids).select('config')
1095 user_accounts = execute_query(self.request, user_accounts_query)
1097 #print user_accounts
1099 for user_account in user_accounts:
1100 config = json.loads(user_account['config'])
1102 if 'authority_credentials' in config:
1103 for authority_hrn, credential in config['authority_credentials'].items():
1104 #if credential is not expired:
1105 credential_authorities.add(authority_hrn)
1107 # credential_authorities_expired.add(authority_hrn)
1108 if 'delegated_authority_credentials' in config:
1109 for authority_hrn, credential in config['delegated_authority_credentials'].items():
1110 #if credential is not expired:
1111 credential_authorities.add(authority_hrn)
1113 # credential_authorities_expired.add(authority_hrn)
1115 print 'credential_authorities =', credential_authorities
1116 print 'credential_authorities_expired =', credential_authorities_expired
1118 # ** Where am I a PI **
1119 # For this we need to ask SFA (of all authorities) = PI function
1120 pi_authorities_query = Query.get('user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
1121 pi_authorities_tmp = execute_query(self.request, pi_authorities_query)
1122 pi_authorities = set()
1123 for pa in pi_authorities_tmp:
1124 pi_authorities |= set(pa['pi_authorities'])
1126 print "pi_authorities =", pi_authorities
1128 # My authorities + I have a credential
1129 pi_credential_authorities = pi_authorities & credential_authorities
1130 pi_no_credential_authorities = pi_authorities - credential_authorities - credential_authorities_expired
1131 pi_expired_credential_authorities = pi_authorities & credential_authorities_expired
1132 # Authorities I've been delegated PI rights
1133 pi_delegation_credential_authorities = credential_authorities - pi_authorities
1134 pi_delegation_expired_authorities = credential_authorities_expired - pi_authorities
1136 print "pi_credential_authorities =", pi_credential_authorities
1137 print "pi_no_credential_authorities =", pi_no_credential_authorities
1138 print "pi_expired_credential_authorities =", pi_expired_credential_authorities
1139 print "pi_delegation_credential_authorities = ", pi_delegation_credential_authorities
1140 print "pi_delegation_expired_authorities = ", pi_delegation_expired_authorities
1142 # Summary intermediary
1143 pi_my_authorities = pi_credential_authorities | pi_no_credential_authorities | pi_expired_credential_authorities
1144 pi_delegation_authorities = pi_delegation_credential_authorities | pi_delegation_expired_authorities
1147 print "pi_my_authorities = ", pi_my_authorities
1148 print "pi_delegation_authorities = ", pi_delegation_authorities
1151 queried_pending_authorities = pi_my_authorities | pi_delegation_authorities
1153 print "queried_pending_authorities = ", queried_pending_authorities
1155 # Pending requests + authorities
1156 #pending_users = PendingUser.objects.filter(authority_hrn__in = queried_pending_authorities).all()
1157 #pending_slices = PendingSlice.objects.filter(authority_hrn__in = queried_pending_authorities).all()
1158 pending_users = PendingUser.objects.all()
1159 pending_slices = PendingSlice.objects.all()
1161 # Dispatch requests and build the proper structure for the template:
1163 print "pending users =", pending_users
1164 print "pending slices =", pending_slices
1166 for user in pending_users:
1167 auth_hrn = user.authority_hrn
1170 request['type'] = 'user'
1171 request['id'] = 'TODO' # XXX in DB ?
1172 request['timestamp'] = 'TODO' # XXX in DB ?
1173 request['details'] = "%s %s <%s>" % (user.first_name, user.last_name, user.email)
1175 if auth_hrn in pi_my_authorities:
1176 dest = ctx_my_authorities
1178 # define the css class
1179 if auth_hrn in pi_credential_authorities:
1180 request['allowed'] = 'allowed'
1181 elif auth_hrn in pi_expired_credential_authorities:
1182 request['allowed'] = 'expired'
1183 else: # pi_no_credential_authorities
1184 request['allowed'] = 'denied'
1186 elif auth_hrn in pi_delegation_authorities:
1187 dest = ctx_delegation_authorities
1189 if auth_hrn in pi_delegation_credential_authorities:
1190 request['allowed'] = 'allowed'
1191 else: # pi_delegation_expired_authorities
1192 request['allowed'] = 'expired'
1197 if not auth_hrn in dest:
1199 print "auth_hrn [%s] was added %r" % (auth_hrn, request)
1200 dest[auth_hrn].append(request)
1202 for slice in pending_slices:
1203 auth_hrn = slice.authority_hrn
1205 auth_hrn = "ple.upmc" # XXX HARDCODED
1208 request['type'] = 'slice'
1209 request['id'] = 'TODO' # XXX in DB ?
1210 request['timestamp'] = 'TODO' # XXX in DB ?
1211 request['details'] = "Number of nodes: %d -- Type of nodes: %s<br/>%s" % ('TODO', 'TODO', 'TODO') # XXX
1212 if auth_hrn in pi_my_authorities:
1213 dest = ctx_my_authorities
1215 # define the css class
1216 if auth_hrn in pi_credential_authorities:
1217 request['allowed'] = 'allowed'
1218 elif auth_hrn in pi_expired_credential_authorities:
1219 request['allowed'] = 'expired'
1220 else: # pi_no_credential_authorities
1221 request['allowed'] = 'denied'
1223 elif auth_hrn in pi_delegation_authorities:
1224 dest = ctx_delegation_authorities
1226 if auth_hrn in pi_delegation_credential_authorities:
1227 request['allowed'] = 'allowed'
1228 else: # pi_delegation_expired_authorities
1229 request['allowed'] = 'expired'
1231 if not auth_hrn in dest:
1233 dest[auth_hrn].append(request)
1235 context = super(ValidatePendingView, self).get_context_data(**kwargs)
1236 context['my_authorities'] = ctx_my_authorities
1237 context['delegation_authorities'] = ctx_delegation_authorities
1239 # XXX This is repeated in all pages
1240 # more general variables expected in the template
1241 context['title'] = 'Test view that combines various plugins'
1242 # the menu items on the top
1243 context['topmenu_items'] = topmenu_items('Dashboard', self.request)
1244 # so we can sho who is logged
1245 context['username'] = the_user(self.request)
1247 # XXX We need to prepare the page for queries
1248 #context.update(page.prelude_env())