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
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 portal.actions import authority_get_pi_emails, get_request_by_authority
44 from manifold.core.query import Query
45 from manifold.manifoldapi import execute_query
46 from unfold.page import Page
47 from myslice.viewutils import topmenu_items, the_user
48 from django.http import HttpResponseRedirect, HttpResponse
50 from M2Crypto import Rand, RSA, BIO
53 class DashboardView(TemplateView):
54 template_name = "dashboard.html"
56 def get_context_data(self, **kwargs):
57 # We might have slices on different registries with different user accounts
58 # 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
59 # Different registries mean different identities, unless we identify via SFA HRN or have associated the user email to a single hrn
61 #messages.info(self.request, 'You have logged in')
62 page = Page(self.request)
65 #slice_query = Query().get('slice').filter_by('user.user_hrn', 'contains', user_hrn).select('slice_hrn')
66 slice_query = Query().get('user').filter_by('user_hrn', '==', '$user_hrn').select('user_hrn', 'slice.slice_hrn')
67 auth_query = Query().get('network').select('network_hrn')
68 print "AUTH QUERY =====================", auth_query
69 print "filter", auth_query.filters
70 page.enqueue_query(slice_query)
71 page.enqueue_query(auth_query)
73 page.expose_js_metadata()
76 slicelist = SimpleList(
79 key = 'slice.slice_hrn',
83 authlist = SimpleList(
90 context = super(DashboardView, self).get_context_data(**kwargs)
91 context['person'] = self.request.user
92 context['networks'] = authlist.render(self.request)
93 context['slices'] = slicelist.render(self.request)
95 # XXX This is repeated in all pages
96 # more general variables expected in the template
97 context['title'] = 'Test view that combines various plugins'
98 # the menu items on the top
99 context['topmenu_items'] = topmenu_items('Dashboard', self.request)
100 # so we can sho who is logged
101 context['username'] = the_user(self.request)
103 context.update(page.prelude_env())
107 # DEPRECATED #class UserRegisterView(RegistrationView):
109 # DEPRECATED # A registration backend which follows a simple workflow:
111 # DEPRECATED # 1. User signs up, inactive account is created.
113 # DEPRECATED # 2. Email is sent to user with activation link.
115 # DEPRECATED # 3. User clicks activation link, account is now active.
117 # DEPRECATED # Using this backend requires that
119 # DEPRECATED # * ``registration`` be listed in the ``INSTALLED_APPS`` setting
120 # DEPRECATED # (since this backend makes use of models defined in this
121 # DEPRECATED # application).
123 # DEPRECATED # * The setting ``ACCOUNT_ACTIVATION_DAYS`` be supplied, specifying
124 # DEPRECATED # (as an integer) the number of days from registration during
125 # DEPRECATED # which a user may activate their account (after that period
126 # DEPRECATED # expires, activation will be disallowed).
128 # DEPRECATED # * The creation of the templates
129 # DEPRECATED # ``registration/activation_email_subject.txt`` and
130 # DEPRECATED # ``registration/activation_email.txt``, which will be used for
131 # DEPRECATED # the activation email. See the notes for this backends
132 # DEPRECATED # ``register`` method for details regarding these templates.
134 # DEPRECATED # Additionally, registration can be temporarily closed by adding the
135 # DEPRECATED # setting ``REGISTRATION_OPEN`` and setting it to
136 # DEPRECATED # ``False``. Omitting this setting, or setting it to ``True``, will
137 # DEPRECATED # be interpreted as meaning that registration is currently open and
138 # DEPRECATED # permitt ed.
140 # DEPRECATED # Internally, this is accomplished via storing an activation key in
141 # DEPRECATED # an instance of ``registration.models.RegistrationProfile``. See
142 # DEPRECATED # that model and its custom manager for full documentation of its
143 # DEPRECATED # fields and supported operations.
146 # DEPRECATED ## DEPRECATED # form_class = UserRegisterForm
148 # DEPRECATED # def register(self, request, **cleaned_data):
150 # DEPRECATED # Given a username, email address and password, register a new
151 # DEPRECATED # user account, which will initially be inactive.
153 # DEPRECATED # Along with the new ``User`` object, a new
154 # DEPRECATED # ``registration.models.RegistrationProfile`` will be created,
155 # DEPRECATED # tied to that ``User``, containing the activation key which
156 # DEPRECATED # will be used for this account.
158 # DEPRECATED # An email will be sent to the supplied email address; this
159 # DEPRECATED # email should contain an activation link. The email will be
160 # DEPRECATED # rendered using two templates. See the documentation for
161 # DEPRECATED # ``RegistrationProfile.send_activation_email()`` for
162 # DEPRECATED # information about these templates and the contexts provided to
165 # DEPRECATED # After the ``User`` and ``RegistrationProfile`` are created and
166 # DEPRECATED # the activation email is sent, the signal
167 # DEPRECATED # ``registration.signals.user_registered`` will be sent, with
168 # DEPRECATED # the new ``User`` as the keyword argument ``user`` and the
169 # DEPRECATED # class of this backend as the sender.
172 # DEPRECATED # first_name = cleaned_data['first_name']
173 # DEPRECATED # last_name = cleaned_data['last_name']
174 # DEPRECATED # affiliation= cleaned_data['affiliation']
175 # DEPRECATED # email = cleaned_data['email']
176 # DEPRECATED # password = cleaned_data['password1']
178 # DEPRECATED # #password2 = cleaned_data['password2']
179 # DEPRECATED # keypair = cleaned_data['keypair']
181 # DEPRECATED # #if Site._meta.installed:
182 # DEPRECATED # # site = Site.objects.get_current()
183 # DEPRECATED # #else:
184 # DEPRECATED # # site = RequestSite(request)
185 # DEPRECATED # site = None
187 # DEPRECATED # new_user = PendingUser.objects.create_inactive_user(first_name, last_name, email, password, site)
188 # DEPRECATED # signals.user_registered.send(sender=self.__class__,
189 # DEPRECATED # user=new_user,
190 # DEPRECATED # request=request)
191 # DEPRECATED # return new_user
193 # DEPRECATED # def get_context_data(self, **kwargs):
194 # DEPRECATED # context = super(UserRegisterView, self).get_context_data(**kwargs)
195 # DEPRECATED # context['topmenu_items'] = topmenu_items('Register', self.request)
196 # DEPRECATED # context['username'] = the_user (self.request)
197 # DEPRECATED # return context
199 # DEPRECATED # def registration_allowed(self, request):
201 # DEPRECATED # Indicate whether account registration is currently permitted,
202 # DEPRECATED # based on the value of the setting ``REGISTRATION_OPEN``. This
203 # DEPRECATED # is determined as follows:
205 # DEPRECATED # * If ``REGISTRATION_OPEN`` is not specified in settings, or is
206 # DEPRECATED # set to ``True``, registration is permitted.
208 # DEPRECATED # * If ``REGISTRATION_OPEN`` is both specified and set to
209 # DEPRECATED # ``False``, registration is not permitted.
212 # DEPRECATED # return getattr(settings, 'REGISTRATION_OPEN', True)
214 # DEPRECATED # def get_success_url(self, request, user):
216 # DEPRECATED # Return the name of the URL to redirect to after successful
217 # DEPRECATED # user registration.
220 # DEPRECATED # return ('user_register_complete', (), {})
223 # DEPRECATED #class UserValidateView(ActivationView):
224 # DEPRECATED # def activate(self, request, activation_key):
226 # DEPRECATED # Given an an activation key, look up and activate the user
227 # DEPRECATED # account corresponding to that key (if possible).
229 # DEPRECATED # After successful activation, the signal
230 # DEPRECATED # ``registration.signals.user_activated`` will be sent, with the
231 # DEPRECATED # newly activated ``User`` as the keyword argument ``user`` and
232 # DEPRECATED # the class of this backend as the sender.
235 # DEPRECATED # activated_user = RegistrationProfile.objects.activate_user(activation_key)
236 # DEPRECATED # if activated_user:
237 # DEPRECATED # signals.user_activated.send(sender=self.__class__,
238 # DEPRECATED # user=activated_user,
239 # DEPRECATED # request=request)
240 # DEPRECATED # return activated_user
242 # DEPRECATED # def get_success_url(self, request, user):
243 # DEPRECATED # return ('registration_activation_complete', (), {})
246 # DEPRECATED #from portal.portalpage import PortalPage
247 # DEPRECATED #from plugins.wizard import Wizard
248 # DEPRECATED #from plugins.form import CreateForm
249 # DEPRECATED #from plugins.raw.raw import Raw # XXX
251 # DEPRECATED #from myslice.viewutils import the_user
253 # DEPRECATED #from django.template.loader import render_to_string
254 # DEPRECATED #from django.template import RequestContext
255 # DEPRECATED #from django.views import generic
257 # DEPRECATED #from django.contrib.formtools.wizard.views import NamedUrlSessionWizardView
258 # DEPRECATED ##from django.core.files.storage import FileSystemStorage
259 # DEPRECATED #from django.core.files.storage import default_storage
261 # DEPRECATED ##class MerlinWizard(NamedUrlSessionWizardView):
266 # DEPRECATED ## @classonlymethod
267 # DEPRECATED ## def as_view(cls, *args, **kwargs):
268 # DEPRECATED ## kwargs.update({
269 # DEPRECATED ## 'form_list': [
270 # DEPRECATED ## NameForm,
271 # DEPRECATED ## QuestForm,
272 # DEPRECATED ## ColorForm,
274 # DEPRECATED ## 'url_name': 'merlin_wizard'
276 # DEPRECATED ## return super(MerlinWizard, cls).as_view(*args, **kwargs)
278 # DEPRECATED #class UserRegisterWizardView(NamedUrlSessionWizardView):
279 # DEPRECATED ##class UserRegisterWizardView(LoginRequiredMixin, NamedUrlSessionWizardView):
280 # DEPRECATED # # Notice that I specify a file storage instance. If you don't specify this,
281 # DEPRECATED # # and you need to support FileField or ImageField in your forms, you'll get
282 # DEPRECATED # # errors from Django. This is something else I think could be handled by
283 # DEPRECATED # # the views better. Seems to me that it should just use whatever the
284 # DEPRECATED # # default/specified storage is for the rest of your project/application.
285 # DEPRECATED # file_storage = default_storage # FileSystemStorage()
286 # DEPRECATED # template_name = "register_user_wizard.html"
288 # DEPRECATED # def done(self, form_list, **kwargs):
289 # DEPRECATED # step1_form = form_list[0]
290 # DEPRECATED # step2_form = form_list[1]
292 # DEPRECATED # productext = self.create_product(product_form)
293 # DEPRECATED # shippings = self.create_shippings(productext, shipping_forms)
294 # DEPRECATED # images = self.create_images(productext, image_forms)
296 # DEPRECATED # if all([productext, shippings, images]):
297 # DEPRECATED # del self.request.session["wizard_product_wizard_view"]
299 # DEPRECATED # messages.success(self.request,
300 # DEPRECATED # _("Your product has been created."))
301 # DEPRECATED # return HttpResponseRedirect(self.get_success_url(productext))
303 # DEPRECATED # messages.error(self.request, _("Something went wrong creating your "
304 # DEPRECATED # "product. Please try again or contact support."))
305 # DEPRECATED # return HttpResponseRedirect(reverse("register_wizard"))
307 # DEPRECATED # #def get_form_kwargs(self, step):
308 # DEPRECATED # # if step == "product":
309 # DEPRECATED # # return {"user": self.request.user}
310 # DEPRECATED # # return {}
312 # DEPRECATED ## The portal should hook the slice and user creation pages
314 # DEPRECATED #def register_user(request):
316 # DEPRECATED # if request.method == 'POST':
317 # DEPRECATED # form = UserRegisterForm(request.POST) # Nous reprenons les données
318 # DEPRECATED # if form.is_valid():
319 # DEPRECATED # first_name = form.cleaned_data['first_name']
320 # DEPRECATED # last_name = form.cleaned_data['last_name']
321 # DEPRECATED # email = form.cleaned_data['email']
322 # DEPRECATED # password = form.cleaned_data['password']
323 # DEPRECATED # password2 = form.cleaned_data['password2']
324 # DEPRECATED # keypair = form.cleaned_data['keypair']
325 # DEPRECATED # ## Ici nous pouvons traiter les données du formulaire
326 # DEPRECATED # #sujet = form.cleaned_data['sujet']
327 # DEPRECATED # #message = form.cleaned_data['message']
328 # DEPRECATED # #envoyeur = form.cleaned_data['envoyeur']
329 # DEPRECATED # #renvoi = form.cleaned_data['renvoi']
330 # DEPRECATED # ## Nous pourrions ici envoyer l'e-mail grâce aux données que nous venons de récupérer
331 # DEPRECATED # #envoi = True
333 # DEPRECATED # form = UserRegisterForm()
334 # DEPRECATED # return render(request, 'register_user.html', locals())
336 # DEPRECATED #def index(request):
338 # DEPRECATED # WIZARD_TITLE = 'User registration'
339 # DEPRECATED # STEP1_TITLE = 'Enter your details'
340 # DEPRECATED # STEP2_TITLE = 'Select your institution'
341 # DEPRECATED # STEP3_TITLE = 'Authentication'
342 # DEPRECATED # STEP4_TITLE = 'Request a slice (optional)'
343 # DEPRECATED # STEP5_TITLE = 'Waiting for validation'
344 # DEPRECATED # STEP6_TITLE = 'Account validated'
346 # DEPRECATED # STEP0 = render_to_string('account_validated.html', context_instance=RequestContext(request))
347 # DEPRECATED # STEP2_HTML = """
348 # DEPRECATED # coucou
350 # DEPRECATED # STEP4 = """
353 # DEPRECATED # STEP5 = render_to_string('account_validated.html', context_instance=RequestContext(request))
355 # DEPRECATED # p = PortalPage(request)
357 # DEPRECATED # # This is redundant with the Wizard title
358 # DEPRECATED # p << "<h3>User registration</h3>"
360 # DEPRECATED # sons = []
361 # DEPRECATED # start_step = 1
363 # DEPRECATED # # STEP 1
364 # DEPRECATED # # If the user already exists (is logged), let's display a summary of his account details
365 # DEPRECATED # # Otherwise propose a form to fill in
366 # DEPRECATED # if the_user(request):
367 # DEPRECATED # # Fill a disabled form with user info
368 # DEPRECATED # # Please logout to register another user
369 # DEPRECATED # sons.append(Raw(page=p, title=STEP1_TITLE, togglable=False, html=STEP0))
370 # DEPRECATED # start_step += 1
372 # DEPRECATED # # We could pass a list of fields also, instead of retrieving them from metadata
373 # DEPRECATED # # Otherwise we need some heuristics to display nice forms
374 # DEPRECATED # # XXX Could we log the user in after the form is validated ?
375 # DEPRECATED # # XXX Explain the password is for XXX
376 # DEPRECATED # field_list = [{
377 # DEPRECATED # 'name' : 'First name',
378 # DEPRECATED # 'field' : 'firstname',
379 # DEPRECATED # 'type' : 'text',
380 # DEPRECATED # 'validate_rx' : '^[a-zA-Z -]+$',
381 # DEPRECATED # 'validate_err': 'Your first name must be comprised of letters only',
382 # DEPRECATED # 'description' : 'Enter your first name',
384 # DEPRECATED # 'name' : 'Last name',
385 # DEPRECATED # 'field' : 'lastname',
386 # DEPRECATED # 'type' : 'text',
387 # DEPRECATED # 'validate_rx' : '^[a-zA-Z -]+$',
388 # DEPRECATED # 'validate_err': 'Your last name must be comprised of letters only',
389 # DEPRECATED # 'description' : 'Enter your last name',
391 # DEPRECATED # 'name' : 'Email',
392 # DEPRECATED # 'field' : 'email',
393 # DEPRECATED # 'type' : 'text',
394 # DEPRECATED # 'description' : 'Enter your email address',
396 # DEPRECATED # 'name' : 'Password',
397 # DEPRECATED # 'field' : 'password',
398 # DEPRECATED # 'type' : 'password',
399 # DEPRECATED # 'description' : 'Enter your password',
401 # DEPRECATED # 'name' : 'Confirm password',
402 # DEPRECATED # 'field' : 'password2',
403 # DEPRECATED # 'type' : 'password',
404 # DEPRECATED # 'description' : 'Enter your password again',
406 # DEPRECATED # sons.append(CreateForm(page = p, title = STEP1_TITLE, togglable = False, object = 'local:user', fields = field_list))
408 # DEPRECATED # # STEP 2
409 # DEPRECATED # # If the user already exists (is logged), let's display a summary of its institution
410 # DEPRECATED # # Otherwise propose a form to fill in (we should base our selection on the email)
411 # DEPRECATED # if the_user(request):
412 # DEPRECATED # # Fill a disabled form with institution
413 # DEPRECATED # # Please logout to register another user
414 # DEPRECATED # sons.append(Raw(page=p, title=STEP2_TITLE, togglable=False, html="User created"))
415 # DEPRECATED # start_step += 1
417 # DEPRECATED # sons.append(CreateForm(page = p, title = STEP2_TITLE, togglable = False, object = 'slice')) #institution'))
419 # DEPRECATED # # STEP3
420 # DEPRECATED # # Please should your prefered authentication method
421 # DEPRECATED # # This step should allow the user to either choose the user or managed mode in MySlice
422 # DEPRECATED # sons.append(Raw(page = p, title = STEP3_TITLE, togglable = False, html = STEP2_HTML))
424 # DEPRECATED # # Step 4: Request a slice (optional)
425 # DEPRECATED # sons.append(CreateForm(page = p, title = STEP4_TITLE, togglable = False, object = 'slice'))
427 # DEPRECATED # # Step 5: Your request is waiting for validation
428 # DEPRECATED # # Periodic refresh
429 # DEPRECATED # sons.append(Raw(page = p, title = STEP5_TITLE, togglable = False, html = STEP4))
431 # DEPRECATED # # Step 6: Account validation = welcome for newly validated users
432 # DEPRECATED # # . delegation
433 # DEPRECATED # # . platforms
434 # DEPRECATED # # . slice
435 # DEPRECATED # # . pointers
436 # DEPRECATED # sons.append(Raw(page = p, title = STEP6_TITLE, togglable = False, html = STEP5))
438 # DEPRECATED # wizard = Wizard(
439 # DEPRECATED # page = p,
440 # DEPRECATED # title = WIZARD_TITLE,
441 # DEPRECATED # togglable = False,
442 # DEPRECATED # sons = sons,
443 # DEPRECATED # start_step = start_step,
446 # DEPRECATED # p << wizard.render(request) # in portal page if possible
448 # DEPRECATED # return p.render()
451 # DEPRECATED ## view for my_account
452 # DEPRECATED # class MyAccountView(TemplateView):
453 # DEPRECATED # template_name = "my_account.html"
455 # DEPRECATED # def from_process(self, request, **cleaned_data):
456 # DEPRECATED # #if request.method == 'POST':
457 # DEPRECATED # # if request.POST['submit_name']:
458 # DEPRECATED # if 'fname' in request.POST:
459 # DEPRECATED # messsag= "Got Name"
460 # DEPRECATED # #return render(request, 'portal/my_account.html')
461 # DEPRECATED # #response = HttpResponse("Here's the text of the Web page.")
462 # DEPRECATED # return HttpResponse(message)
464 # DEPRECATED # def get_context_data(self, **kwargs):
465 # DEPRECATED # page = Page(self.request)
466 # DEPRECATED # context = super(MyAccountView, self).get_context_data(**kwargs)
467 # DEPRECATED # context['person'] = self.request.user
468 # DEPRECATED # # XXX This is repeated in all pages
469 # DEPRECATED # # more general variables expected in the template
470 # DEPRECATED # context['title'] = 'User Profile Page'
471 # DEPRECATED # # the menu items on the top
472 # DEPRECATED # context['topmenu_items'] = topmenu_items('my_account', self.request)
473 # DEPRECATED # # so we can sho who is logged
474 # DEPRECATED # context['username'] = the_user(self.request)
475 # DEPRECATED # context.update(page.prelude_env())
476 # DEPRECATED # return context
480 # View for my_account form
481 def my_account(request):
482 return render(request, 'my_account.html', {
484 'topmenu_items': topmenu_items('My Account', request),
485 'username': the_user (request)
489 class PlatformsView(TemplateView):
490 template_name = "platforms.html"
492 def get_context_data(self, **kwargs):
493 page = Page(self.request)
495 network_query = Query().get('local:platform').filter_by('disabled', '==', '0').select('platform','platform_longname','gateway_type')
496 page.enqueue_query(network_query)
498 page.expose_js_metadata()
499 page.expose_queries()
500 networklist = Hazelnut(
503 domid = 'checkboxes',
504 # this is the query at the core of the slice list
505 query = network_query,
506 query_all = network_query,
508 datatables_options = {
509 # for now we turn off sorting on the checkboxes columns this way
510 # this of course should be automatic in hazelnut
511 'aoColumns' : [None, None, None, None, {'bSortable': False}],
512 'iDisplayLength' : 25,
513 'bLengthChange' : True,
517 # networklist = SimpleList(
521 # query = network_query,
524 context = super(PlatformsView, self).get_context_data(**kwargs)
525 context['person'] = self.request.user
526 context['networks'] = networklist.render(self.request)
528 # XXX This is repeated in all pages
529 # more general variables expected in the template
530 context['title'] = 'Platforms connected to MySlice'
531 # the menu items on the top
532 context['topmenu_items'] = topmenu_items('Platforms', self.request)
533 # so we can sho who is logged
534 context['username'] = the_user(self.request)
536 context.update(page.prelude_env())
540 # View for 1 platform and its details
541 class PlatformView(TemplateView):
542 template_name = "platform.html"
544 def get_context_data(self, **kwargs):
545 page = Page(self.request)
547 for key, value in kwargs.iteritems():
548 print "%s = %s" % (key, value)
549 if key == "platformname":
552 network_query = Query().get('local:platform').filter_by('platform', '==', platformname).select('platform','platform_longname','gateway_type')
553 page.enqueue_query(network_query)
555 page.expose_js_metadata()
556 page.expose_queries()
557 networklist = Hazelnut(
560 domid = 'checkboxes',
561 # this is the query at the core of the slice list
562 query = network_query,
563 query_all = network_query,
565 datatables_options = {
566 # for now we turn off sorting on the checkboxes columns this way
567 # this of course should be automatic in hazelnut
568 'aoColumns' : [None, None, None, None, {'bSortable': False}],
569 'iDisplayLength' : 25,
570 'bLengthChange' : True,
574 # networklist = SimpleList(
578 # query = network_query,
581 context = super(PlatformView, self).get_context_data(**kwargs)
582 context['person'] = self.request.user
583 context['networks'] = networklist.render(self.request)
585 # XXX This is repeated in all pages
586 # more general variables expected in the template
587 context['title'] = 'Platforms connected to MySlice'
588 # the menu items on the top
589 context['topmenu_items'] = topmenu_items('Platforms', self.request)
590 # so we can sho who is logged
591 context['username'] = the_user(self.request)
593 context.update(page.prelude_env())
597 #my_acc form value processing
598 def acc_process(request):
599 # getting the user_id from the session [now hardcoded]
600 get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
601 if 'submit_name' in request.POST:
602 edited_first_name = request.POST['fname']
603 edited_last_name = request.POST['lname']
604 #email = 'test_email@gmail.com'
605 #password = 'test_pp'
606 #message = 'F_Name: %s L_name: %s dummy_pp: %s' % (first_name, last_name, password)
609 # insert into DB [needed for registration page]
610 #approach borrowed from register view
611 #new_user = PendingUser.objects.create_inactive_user(edited_first_name, edited_last_name, email, password, site)
612 #conventional approach
613 #b = PendingUser(first_name=edited_first_name, last_name=edited_last_name)
616 # select and update [will be used throughout this view]
617 # select the logged in user [for the moment hard coded]
618 #get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
619 # update first and last name
620 get_user.first_name = edited_first_name
621 get_user.last_name = edited_last_name
624 return HttpResponse('Success: Name Updated!!')
625 elif 'submit_pass' in request.POST:
626 edited_password = request.POST['password']
627 # select the logged in user [for the moment hard coded]
628 #get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
630 get_user.password = edited_password
632 return HttpResponse('Success: Password Changed!!')
633 elif 'generate' in request.POST:
635 #from M2Crypto import Rand, RSA, BIO
639 def blank_callback():
640 "Replace the default dashes"
644 Rand.rand_seed (os.urandom (KEY_LENGTH))
646 key = RSA.gen_key (KEY_LENGTH, 65537, blank_callback)
647 # Create memory buffers
648 pri_mem = BIO.MemoryBuffer()
649 pub_mem = BIO.MemoryBuffer()
650 # Save keys to buffers
651 key.save_key_bio(pri_mem, None)
652 key.save_pub_key_bio(pub_mem)
655 public_key = pub_mem.getvalue()
656 private_key = pri_mem.getvalue()
658 keypair = '{"user_public_key":"'+ public_key + '", "user_private_key":"'+ private_key + '"}'
659 keypair = re.sub("\r", "", keypair)
660 keypair = re.sub("\n", "\\n", keypair)
661 #keypair = keypair.rstrip('\r\n')
662 keypair = ''.join(keypair.split())
663 get_user.keypair = keypair
665 return HttpResponse('Success: New Keypair Generated! %s' % keypair)
667 elif 'upload_key' in request.POST:
668 up_file = request.FILES['pubkey']
669 file_content = up_file.read()
670 file_name = up_file.name
671 file_extension = os.path.splitext(file_name)[1]
672 allowed_extension = ['.pub','.txt']
673 if file_extension in allowed_extension and re.search(r'ssh-rsa',file_content):
674 file_content = '{"user_public_key":"'+ file_content +'"}'
675 file_content = re.sub("\r", "", file_content)
676 file_content = re.sub("\n", "\\n",file_content)
677 file_content = ''.join(file_content.split())
678 get_user.keypair = file_content
680 return HttpResponse('Success: Publickey uploaded! Old records overwritten')
682 return HttpResponse('Please upload a valid RSA public key [.txt or .pub].')
685 message = 'You submitted an empty form.'
686 return HttpResponse(message)
688 def register_4m_f4f(request):
691 authorities_query = Query.get('authority').filter_by('authority_hrn', 'included', ['ple.inria', 'ple.upmc']).select('name', 'authority_hrn')
692 #authorities_query = Query.get('authority').select('authority_hrn')
693 authorities = execute_query(request, authorities_query)
695 if request.method == 'POST':
696 # We shall use a form here
698 #get_email = PendingUser.objects.get(email)
699 reg_fname = request.POST.get('firstname', '')
700 reg_lname = request.POST.get('lastname', '')
701 reg_aff = request.POST.get('affiliation','')
702 reg_auth = request.POST.get('authority_hrn', '')
703 reg_email = request.POST.get('email','').lower()
705 #POST value validation
706 if (re.search(r'^[\w+\s.@+-]+$', reg_fname)==None):
707 errors.append('First Name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
708 #return HttpResponse("Only Letters, Numbers, - and _ allowd in First Name")
709 #return render(request, 'register_4m_f4f.html')
710 if (re.search(r'^[\w+\s.@+-]+$', reg_lname) == None):
711 errors.append('Last Name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
712 #return HttpResponse("Only Letters, Numbers, - and _ is allowed in Last name")
713 #return render(request, 'register_4m_f4f.html')
714 if (re.search(r'^[\w+\s.@+-]+$', reg_aff) == None):
715 errors.append('Affiliation may contain only letters, numbers, spaces and @/./+/-/_ characters.')
716 #return HttpResponse("Only Letters, Numbers and _ is allowed in Affiliation")
717 #return render(request, 'register_4m_f4f.html')
718 # XXX validate authority hrn !!
719 if PendingUser.objects.filter(email__iexact=reg_email):
720 errors.append('Email already registered.Please provide a new email address.')
721 #return HttpResponse("Email Already exists")
722 #return render(request, 'register_4m_f4f.html')
723 if 'generate' in request.POST['question']:
725 #from M2Crypto import Rand, RSA, BIO
729 def blank_callback():
730 "Replace the default dashes"
734 Rand.rand_seed (os.urandom (KEY_LENGTH))
736 key = RSA.gen_key (KEY_LENGTH, 65537, blank_callback)
737 # Create memory buffers
738 pri_mem = BIO.MemoryBuffer()
739 pub_mem = BIO.MemoryBuffer()
740 # Save keys to buffers
741 key.save_key_bio(pri_mem, None)
742 key.save_pub_key_bio(pub_mem)
744 public_key = pub_mem.getvalue()
745 private_key = pri_mem.getvalue()
747 keypair = '{"user_public_key":"'+ public_key + '", "user_private_key":"'+ private_key + '"}'
748 keypair = re.sub("\r", "", keypair)
749 keypair = re.sub("\n", "\\n", keypair)
750 #keypair = keypair.rstrip('\r\n')
751 keypair = ''.join(keypair.split())
752 #return HttpResponse(keypair)
754 up_file = request.FILES['user_public_key']
755 file_content = up_file.read()
756 file_name = up_file.name
757 file_extension = os.path.splitext(file_name)[1]
758 allowed_extension = ['.pub','.txt']
759 if file_extension in allowed_extension and re.search(r'ssh-rsa',file_content):
760 keypair = '{"user_public_key":"'+ file_content +'"}'
761 keypair = re.sub("\r", "", keypair)
762 keypair = re.sub("\n", "\\n",keypair)
763 keypair = ''.join(keypair.split())
765 errors.append('Please upload a valid RSA public key [.txt or .pub].')
767 #b = PendingUser(first_name=reg_fname, last_name=reg_lname, affiliation=reg_aff,
768 # email=reg_email, password=request.POST['password'], keypair=keypair)
772 first_name=reg_fname,
775 authority_hrn=reg_auth,
777 password=request.POST['password'],
784 first_name : reg_fname,
785 last_name : reg_lname,
786 affiliation : reg_aff,
787 authority_hrn: reg_auth,
790 cc_myself : True # form.cleaned_data['cc_myself']
793 recipients = authority_get_pi_emails(authority_hrn)
795 recipients.append(ctx['email'])
797 msg = render_to_string('user_request_email.txt', ctx)
798 send_mail("Onelab New User request submitted", msg, email, recipients)
800 return render(request, 'user_register_complete.html')
802 return render(request, 'register_4m_f4f.html',{
803 'topmenu_items': topmenu_items('Register', request),
805 'firstname': request.POST.get('firstname', ''),
806 'lastname': request.POST.get('lastname', ''),
807 'affiliation': request.POST.get('affiliation', ''),
808 'authority_hrn': request.POST.get('authority_hrn', ''),
809 'email': request.POST.get('email', ''),
810 'password': request.POST.get('password', ''),
811 'authorities': authorities
815 # view for contact form
816 def contact(request):
817 if request.method == 'POST': # If the form has been submitted...
818 form = ContactForm(request.POST) # A form bound to the POST data
819 if form.is_valid(): # All validation rules pass
820 # Process the data in form.cleaned_data
821 first_name = form.cleaned_data['first_name']
822 last_name = form.cleaned_data['last_name']
823 affiliation = form.cleaned_data['affiliation']
824 subject = form.cleaned_data['subject']
825 message = form.cleaned_data['message']
826 email = form.cleaned_data['email'] # email of the sender
827 cc_myself = form.cleaned_data['cc_myself']
829 #recipients = authority_get_pi_emails(authority_hrn)
830 recipients = ['yasin.upmc@gmail.com']
832 recipients.append(email)
834 from django.core.mail import send_mail
835 send_mail("Onelab user submitted a query ", [first_name,last_name,affiliation,subject,message], email, recipients)
836 return render(request,'contact_sent.html') # Redirect after POST
838 form = ContactForm() # An unbound form
840 return render(request, 'contact.html', {
842 'topmenu_items': topmenu_items('Contact Us', request),
843 'username': the_user (request)
848 def slice_request(request):
851 authorities_query = Query.get('authority').filter_by('authority_hrn', 'included', ['ple.inria', 'ple.upmc']).select('name', 'authority_hrn')
852 #authorities_query = Query.get('authority').select('authority_hrn')
853 authorities = execute_query(request, authorities_query)
855 authority_hrn_tuple = []
856 for authority in authorities:
857 authority_hrn_tuple.append((authority['authority_hrn'], authority['name']))
858 authority_hrn_initial = {'authority_hrn': authority_hrn_tuple}
860 # request.POST or None ?
861 if request.method == 'POST':
862 # The form has been submitted
863 form = SliceRequestForm(request.POST, initial=authority_hrn_initial)
866 slice_name = form.cleaned_data['slice_name']
867 authority_hrn = form.cleaned_data['authority_hrn']
868 number_of_nodes = form.cleaned_data['number_of_nodes']
869 type_of_nodes = form.cleaned_data['type_of_nodes']
870 purpose = form.cleaned_data['purpose']
873 slice_name = slice_name,
874 authority_hrn = authority_hrn,
875 number_of_nodes = number_of_nodes,
876 type_of_nodes = type_of_nodes,
881 # All validation rules pass; process data in form.cleaned_data
882 # slice_name, number_of_nodes, type_of_nodes, purpose
883 email = form.cleaned_data['email'] # email of the sender
884 cc_myself = form.cleaned_data['cc_myself']
886 # The recipients are the PI of the authority
887 recipients = authority_get_pi_emails(authority_hrn)
888 #recipients = ['yasin.upmc@gmail.com','jordan.auge@lip6.fr']
890 recipients.append(email)
891 msg = render_to_string('slice_request_email.txt', form.cleaned_data)
892 send_mail("Onelab New Slice request form submitted", msg, email, recipients)
894 return render(request,'slicereq_recvd.html') # Redirect after POST
896 form = SliceRequestForm(initial=authority_hrn_initial)
899 # template_env['form'] = form
900 # template_env['topmenu_items'] = topmenu_items('Request a slice', request)
901 # template_env['unfold1_main'] = render(request, 'slice_request_.html', {
904 # from django.shortcuts import render_to_response
905 # from django.template import RequestContext
906 # return render_to_response ('view-unfold1.html',template_env,
907 # context_instance=RequestContext(request))
909 return render(request, 'slice_request.html', {
911 'topmenu_items': topmenu_items('Request a slice', request),
912 'username': the_user (request)
916 class PresViewView(TemplateView):
917 template_name = "view-unfold1.html"
919 def get_context_data(self, **kwargs):
921 page = Page(self.request)
923 pres_view = PresView(page = page)
925 context = super(PresViewView, self).get_context_data(**kwargs)
927 #context['ALL_STATIC'] = "all_static"
928 context['unfold1_main'] = pres_view.render(self.request)
930 # XXX This is repeated in all pages
931 # more general variables expected in the template
932 context['title'] = 'Test view that combines various plugins'
933 # the menu items on the top
934 context['topmenu_items'] = topmenu_items('PresView', self.request)
935 # so we can sho who is logged
936 context['username'] = the_user(self.request)
938 prelude_env = page.prelude_env()
939 context.update(prelude_env)
943 def json_me(config_file,type):
945 for ligne in config_file:
946 if not ligne.startswith('#'):
947 args = ligne.split(';')
948 json_answer += str('{ "name": "' + args[0] + '" ,"id":"' + args[1] + '" ,"descriptif":"' + args[2]+'"')
950 json_answer += str(',"contraints":')
952 json_answer += str('""')
954 json_answer += str(args[3])
955 json_answer += str('},')
956 return json_answer[:-1]
959 DIR = '/var/myslice/'
960 STATIC = '%s/config_method_static' % DIR
961 DYNAMIC = '%s/config_method_dynamic' % DIR
962 ANIMATION = '%s/config_method_animation' % DIR
964 def pres_view_methods(request, type):
968 elif type =="static":
969 config = open(STATIC, "r")
970 json_answer = str('{ "options": [')
971 json_answer += str(json_me(config,"static"))
972 json_answer += str('] }')
974 elif type =="dynamic":
975 config = open(DYNAMIC, "r")
976 json_answer = str('{ "options": [')
977 json_answer += str(json_me(config,"dynamic"))
978 json_answer += str('] }')
980 elif type =="animation":
981 config = open(ANIMATION, "r")
982 json_answer = str('{ "options": [')
983 json_answer += str(json_me(config,"animation"))
984 json_answer += str('] }')
987 config = open(STATIC, "r")
988 json_answer = str('{ "static": [')
989 json_answer += str(json_me(config,"static"))
990 json_answer += str('],')
991 json_answer += str('"dynamic": [')
993 config = open(DYNAMIC, "r")
994 json_answer += str(json_me(config,"dynamic"))
995 json_answer += str('],')
996 json_answer += str('"animation": [')
998 config = open(ANIMATION, "r")
999 json_answer += str(json_me(config,"animation"))
1000 json_answer += str('] }')
1004 return HttpResponse (json_answer, mimetype="application/json")
1006 def pres_view_animation(request, constraints, id):
1008 # sites crees depuis 2008
1009 # static.py?contraints=']date_created':1262325600&id='name_id"'
1011 # method = request.getvalue('method') #ex : GetSites
1012 #constraints = "']date_created':1262325600"
1018 # method = 'GetSites'#request.getvalue('method') #ex : GetSites
1019 # constraints = {}#request.getvalue('constraints') // nul = {}
1020 # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
1022 config_file = open(ANIMATION, "r")
1023 for ligne in config_file:
1024 if not ligne.startswith('#'):
1025 ligne = ligne.split('\n')
1026 first = ligne[0].split(';')
1027 if (str(first[1]) == str(id)):
1031 #Les print_method, print_option sont definis par le client (js)
1032 #Les animations acceptent que les connexions anonymous
1033 # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
1034 args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
1037 #Creation d'un objet event
1041 "print_options": event.print_options,
1042 "print_method": event.print_method,
1043 "message": event.data
1048 json_answer = json.dumps(cmd)
1049 return HttpResponse (json_answer, mimetype="application/json")
1051 def pres_view_static(request, constraints, id):
1052 #constraints = "']date_created':1262325600"
1055 # method = 'GetSites'#request.getvalue('method') #ex : GetSites
1056 # constraints = {}#request.getvalue('constraints') // nul = {}
1057 # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
1059 config_file = open(STATIC, "r")
1060 for ligne in config_file:
1061 if not ligne.startswith('#'):
1062 ligne = ligne.split('\n')
1063 first = ligne[0].split(';')
1064 if (str(first[1]) == str(id)):
1068 #Les print_method, print_option sont definis par le client (js)
1069 #Les animations acceptent que les connexions anonymous
1070 # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
1071 args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
1074 #Creation d'un objet event
1078 "print_options": event.print_options,
1079 "print_method": event.print_method,
1080 "message": event.data
1085 json_answer = json.dumps(cmd)
1086 return HttpResponse (json_answer, mimetype="application/json")
1088 class ValidatePendingView(TemplateView):
1089 template_name = "validate_pending.html"
1091 def get_context_data(self, **kwargs):
1092 # We might have slices on different registries with different user accounts
1093 # 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
1094 # Different registries mean different identities, unless we identify via SFA HRN or have associated the user email to a single hrn
1096 #messages.info(self.request, 'You have logged in')
1097 page = Page(self.request)
1099 ctx_my_authorities = {}
1100 ctx_delegation_authorities = {}
1103 # The user need to be logged in
1104 if the_user(self.request):
1105 # Who can a PI validate:
1106 # His own authorities + those he has credentials for.
1107 # In MySlice we need to look at credentials also.
1110 # XXX This will have to be asynchroneous. Need to implement barriers,
1111 # for now it will be sufficient to have it working statically
1113 # get user_id to later on query accounts
1114 # XXX Having real query plan on local tables would simplify all this
1115 # XXX $user_email is still not available for local tables
1116 #user_query = Query().get('local:user').filter_by('email', '==', '$user_email').select('user_id')
1117 user_query = Query().get('local:user').filter_by('email', '==', the_user(self.request)).select('user_id')
1118 user, = execute_query(self.request, user_query)
1119 user_id = user['user_id']
1121 # Query manifold to learn about available SFA platforms for more information
1122 # In general we will at least have the portal
1123 # For now we are considering all registries
1124 all_authorities = []
1126 sfa_platforms_query = Query().get('local:platform').filter_by('gateway_type', '==', 'sfa').select('platform_id', 'platform', 'auth_type')
1127 sfa_platforms = execute_query(self.request, sfa_platforms_query)
1128 for sfa_platform in sfa_platforms:
1129 print "SFA PLATFORM > ", sfa_platform['platform']
1130 if not 'auth_type' in sfa_platform:
1132 auth = sfa_platform['auth_type']
1133 if not auth in all_authorities:
1134 all_authorities.append(auth)
1135 platform_ids.append(sfa_platform['platform_id'])
1137 # We can check on which the user has authoritity credentials = PI rights
1138 credential_authorities = set()
1139 credential_authorities_expired = set()
1141 # User account on these registries
1142 user_accounts_query = Query.get('local:account').filter_by('user_id', '==', user_id).filter_by('platform_id', 'included', platform_ids).select('config')
1143 user_accounts = execute_query(self.request, user_accounts_query)
1145 #print user_accounts
1147 for user_account in user_accounts:
1148 config = json.loads(user_account['config'])
1150 if 'authority_credentials' in config:
1151 for authority_hrn, credential in config['authority_credentials'].items():
1152 #if credential is not expired:
1153 credential_authorities.add(authority_hrn)
1155 # credential_authorities_expired.add(authority_hrn)
1156 if 'delegated_authority_credentials' in config:
1157 for authority_hrn, credential in config['delegated_authority_credentials'].items():
1158 #if credential is not expired:
1159 credential_authorities.add(authority_hrn)
1161 # credential_authorities_expired.add(authority_hrn)
1163 print 'credential_authorities =', credential_authorities
1164 print 'credential_authorities_expired =', credential_authorities_expired
1166 # ** Where am I a PI **
1167 # For this we need to ask SFA (of all authorities) = PI function
1168 pi_authorities_query = Query.get('user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
1169 pi_authorities_tmp = execute_query(self.request, pi_authorities_query)
1170 pi_authorities = set()
1171 for pa in pi_authorities_tmp:
1172 pi_authorities |= set(pa['pi_authorities'])
1174 print "pi_authorities =", pi_authorities
1176 # My authorities + I have a credential
1177 pi_credential_authorities = pi_authorities & credential_authorities
1178 pi_no_credential_authorities = pi_authorities - credential_authorities - credential_authorities_expired
1179 pi_expired_credential_authorities = pi_authorities & credential_authorities_expired
1180 # Authorities I've been delegated PI rights
1181 pi_delegation_credential_authorities = credential_authorities - pi_authorities
1182 pi_delegation_expired_authorities = credential_authorities_expired - pi_authorities
1184 print "pi_credential_authorities =", pi_credential_authorities
1185 print "pi_no_credential_authorities =", pi_no_credential_authorities
1186 print "pi_expired_credential_authorities =", pi_expired_credential_authorities
1187 print "pi_delegation_credential_authorities = ", pi_delegation_credential_authorities
1188 print "pi_delegation_expired_authorities = ", pi_delegation_expired_authorities
1190 # Summary intermediary
1191 pi_my_authorities = pi_credential_authorities | pi_no_credential_authorities | pi_expired_credential_authorities
1192 pi_delegation_authorities = pi_delegation_credential_authorities | pi_delegation_expired_authorities
1195 print "pi_my_authorities = ", pi_my_authorities
1196 print "pi_delegation_authorities = ", pi_delegation_authorities
1199 queried_pending_authorities = pi_my_authorities | pi_delegation_authorities
1201 print "queried_pending_authorities = ", queried_pending_authorities
1203 requests = get_request_by_authority(queried_pending_authorities)
1204 for request in requests:
1205 auth_hrn = request['authority_hrn']
1207 if auth_hrn in pi_my_authorities:
1208 dest = ctx_my_authorities
1210 # define the css class
1211 if auth_hrn in pi_credential_authorities:
1212 request['allowed'] = 'allowed'
1213 elif auth_hrn in pi_expired_credential_authorities:
1214 request['allowed'] = 'expired'
1215 else: # pi_no_credential_authorities
1216 request['allowed'] = 'denied'
1218 elif auth_hrn in pi_delegation_authorities:
1219 dest = ctx_delegation_authorities
1221 if auth_hrn in pi_delegation_credential_authorities:
1222 request['allowed'] = 'allowed'
1223 else: # pi_delegation_expired_authorities
1224 request['allowed'] = 'expired'
1229 if not auth_hrn in dest:
1231 dest[auth_hrn].append(request)
1233 context = super(ValidatePendingView, self).get_context_data(**kwargs)
1234 context['my_authorities'] = ctx_my_authorities
1235 context['delegation_authorities'] = ctx_delegation_authorities
1237 # XXX This is repeated in all pages
1238 # more general variables expected in the template
1239 context['title'] = 'Test view that combines various plugins'
1240 # the menu items on the top
1241 context['topmenu_items'] = topmenu_items('Dashboard', self.request)
1242 # so we can sho who is logged
1243 context['username'] = the_user(self.request)
1245 # XXX We need to prepare the page for queries
1246 #context.update(page.prelude_env())