1 # -*- coding: utf-8 -*-
3 # portal/views.py: views for the portal application
4 # This file is part of the Manifold project.
7 # Jordan Augé <jordan.auge@lip6.fr>
8 # Mohammed Yasin Rahman <mohammed-yasin.rahman@lip6.fr>
9 # Copyright 2013, UPMC Sorbonne Universités / LIP6
11 # This program is free software; you can redistribute it and/or modify it under
12 # the terms of the GNU General Public License as published by the Free Software
13 # Foundation; either version 3, or (at your option) any later version.
15 # This program is distributed in the hope that it will be useful, but WITHOUT
16 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
20 # You should have received a copy of the GNU General Public License along with
21 # this program; see the file COPYING. If not, write to the Free Software
22 # Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 from django.conf import settings
25 from django.contrib.sites.models import Site, RequestSite
26 from django.contrib import messages
27 from django.views.generic import View
28 from django.views.generic.base import TemplateView
29 from django.shortcuts import render
31 from plugins.lists.simplelist import SimpleList
32 from plugins.hazelnut import Hazelnut
33 from plugins.pres_view import PresView
34 from portal.event import Event
37 from portal import signals
38 from portal.forms import SliceRequestForm, ContactForm
39 from portal.util import RegistrationView, ActivationView
40 from portal.models import PendingUser, PendingSlice
41 from manifold.core.query import Query
42 from manifold.manifoldapi import execute_query
43 from unfold.page import Page
44 from myslice.viewutils import topmenu_items, the_user
45 from django.http import HttpResponseRedirect, HttpResponse
47 from M2Crypto import Rand, RSA, BIO
50 class DashboardView(TemplateView):
51 template_name = "dashboard.html"
53 def get_context_data(self, **kwargs):
54 # We might have slices on different registries with different user accounts
55 # We note that this portal could be specific to a given registry, to which we register users, but i'm not sure that simplifies things
56 # Different registries mean different identities, unless we identify via SFA HRN or have associated the user email to a single hrn
58 #messages.info(self.request, 'You have logged in')
59 page = Page(self.request)
62 #slice_query = Query().get('slice').filter_by('user.user_hrn', 'contains', user_hrn).select('slice_hrn')
63 slice_query = Query().get('user').filter_by('user_hrn', '==', '$user_hrn').select('user_hrn', 'slice.slice_hrn')
64 auth_query = Query().get('network').select('network_hrn')
65 print "AUTH QUERY =====================", auth_query
66 print "filter", auth_query.filters
67 page.enqueue_query(slice_query)
68 page.enqueue_query(auth_query)
70 page.expose_js_metadata()
73 slicelist = SimpleList(
76 key = 'slice.slice_hrn',
80 authlist = SimpleList(
87 context = super(DashboardView, self).get_context_data(**kwargs)
88 context['person'] = self.request.user
89 context['networks'] = authlist.render(self.request)
90 context['slices'] = slicelist.render(self.request)
92 # XXX This is repeated in all pages
93 # more general variables expected in the template
94 context['title'] = 'Test view that combines various plugins'
95 # the menu items on the top
96 context['topmenu_items'] = topmenu_items('Dashboard', self.request)
97 # so we can sho who is logged
98 context['username'] = the_user(self.request)
100 context.update(page.prelude_env())
104 # DEPRECATED #class UserRegisterView(RegistrationView):
106 # DEPRECATED # A registration backend which follows a simple workflow:
108 # DEPRECATED # 1. User signs up, inactive account is created.
110 # DEPRECATED # 2. Email is sent to user with activation link.
112 # DEPRECATED # 3. User clicks activation link, account is now active.
114 # DEPRECATED # Using this backend requires that
116 # DEPRECATED # * ``registration`` be listed in the ``INSTALLED_APPS`` setting
117 # DEPRECATED # (since this backend makes use of models defined in this
118 # DEPRECATED # application).
120 # DEPRECATED # * The setting ``ACCOUNT_ACTIVATION_DAYS`` be supplied, specifying
121 # DEPRECATED # (as an integer) the number of days from registration during
122 # DEPRECATED # which a user may activate their account (after that period
123 # DEPRECATED # expires, activation will be disallowed).
125 # DEPRECATED # * The creation of the templates
126 # DEPRECATED # ``registration/activation_email_subject.txt`` and
127 # DEPRECATED # ``registration/activation_email.txt``, which will be used for
128 # DEPRECATED # the activation email. See the notes for this backends
129 # DEPRECATED # ``register`` method for details regarding these templates.
131 # DEPRECATED # Additionally, registration can be temporarily closed by adding the
132 # DEPRECATED # setting ``REGISTRATION_OPEN`` and setting it to
133 # DEPRECATED # ``False``. Omitting this setting, or setting it to ``True``, will
134 # DEPRECATED # be interpreted as meaning that registration is currently open and
135 # DEPRECATED # permitt ed.
137 # DEPRECATED # Internally, this is accomplished via storing an activation key in
138 # DEPRECATED # an instance of ``registration.models.RegistrationProfile``. See
139 # DEPRECATED # that model and its custom manager for full documentation of its
140 # DEPRECATED # fields and supported operations.
143 # DEPRECATED ## DEPRECATED # form_class = UserRegisterForm
145 # DEPRECATED # def register(self, request, **cleaned_data):
147 # DEPRECATED # Given a username, email address and password, register a new
148 # DEPRECATED # user account, which will initially be inactive.
150 # DEPRECATED # Along with the new ``User`` object, a new
151 # DEPRECATED # ``registration.models.RegistrationProfile`` will be created,
152 # DEPRECATED # tied to that ``User``, containing the activation key which
153 # DEPRECATED # will be used for this account.
155 # DEPRECATED # An email will be sent to the supplied email address; this
156 # DEPRECATED # email should contain an activation link. The email will be
157 # DEPRECATED # rendered using two templates. See the documentation for
158 # DEPRECATED # ``RegistrationProfile.send_activation_email()`` for
159 # DEPRECATED # information about these templates and the contexts provided to
162 # DEPRECATED # After the ``User`` and ``RegistrationProfile`` are created and
163 # DEPRECATED # the activation email is sent, the signal
164 # DEPRECATED # ``registration.signals.user_registered`` will be sent, with
165 # DEPRECATED # the new ``User`` as the keyword argument ``user`` and the
166 # DEPRECATED # class of this backend as the sender.
169 # DEPRECATED # first_name = cleaned_data['first_name']
170 # DEPRECATED # last_name = cleaned_data['last_name']
171 # DEPRECATED # affiliation= cleaned_data['affiliation']
172 # DEPRECATED # email = cleaned_data['email']
173 # DEPRECATED # password = cleaned_data['password1']
175 # DEPRECATED # #password2 = cleaned_data['password2']
176 # DEPRECATED # keypair = cleaned_data['keypair']
178 # DEPRECATED # #if Site._meta.installed:
179 # DEPRECATED # # site = Site.objects.get_current()
180 # DEPRECATED # #else:
181 # DEPRECATED # # site = RequestSite(request)
182 # DEPRECATED # site = None
184 # DEPRECATED # new_user = PendingUser.objects.create_inactive_user(first_name, last_name, email, password, site)
185 # DEPRECATED # signals.user_registered.send(sender=self.__class__,
186 # DEPRECATED # user=new_user,
187 # DEPRECATED # request=request)
188 # DEPRECATED # return new_user
190 # DEPRECATED # def get_context_data(self, **kwargs):
191 # DEPRECATED # context = super(UserRegisterView, self).get_context_data(**kwargs)
192 # DEPRECATED # context['topmenu_items'] = topmenu_items('Register', self.request)
193 # DEPRECATED # context['username'] = the_user (self.request)
194 # DEPRECATED # return context
196 # DEPRECATED # def registration_allowed(self, request):
198 # DEPRECATED # Indicate whether account registration is currently permitted,
199 # DEPRECATED # based on the value of the setting ``REGISTRATION_OPEN``. This
200 # DEPRECATED # is determined as follows:
202 # DEPRECATED # * If ``REGISTRATION_OPEN`` is not specified in settings, or is
203 # DEPRECATED # set to ``True``, registration is permitted.
205 # DEPRECATED # * If ``REGISTRATION_OPEN`` is both specified and set to
206 # DEPRECATED # ``False``, registration is not permitted.
209 # DEPRECATED # return getattr(settings, 'REGISTRATION_OPEN', True)
211 # DEPRECATED # def get_success_url(self, request, user):
213 # DEPRECATED # Return the name of the URL to redirect to after successful
214 # DEPRECATED # user registration.
217 # DEPRECATED # return ('user_register_complete', (), {})
220 # DEPRECATED #class UserValidateView(ActivationView):
221 # DEPRECATED # def activate(self, request, activation_key):
223 # DEPRECATED # Given an an activation key, look up and activate the user
224 # DEPRECATED # account corresponding to that key (if possible).
226 # DEPRECATED # After successful activation, the signal
227 # DEPRECATED # ``registration.signals.user_activated`` will be sent, with the
228 # DEPRECATED # newly activated ``User`` as the keyword argument ``user`` and
229 # DEPRECATED # the class of this backend as the sender.
232 # DEPRECATED # activated_user = RegistrationProfile.objects.activate_user(activation_key)
233 # DEPRECATED # if activated_user:
234 # DEPRECATED # signals.user_activated.send(sender=self.__class__,
235 # DEPRECATED # user=activated_user,
236 # DEPRECATED # request=request)
237 # DEPRECATED # return activated_user
239 # DEPRECATED # def get_success_url(self, request, user):
240 # DEPRECATED # return ('registration_activation_complete', (), {})
243 # DEPRECATED #from portal.portalpage import PortalPage
244 # DEPRECATED #from plugins.wizard import Wizard
245 # DEPRECATED #from plugins.form import CreateForm
246 # DEPRECATED #from plugins.raw.raw import Raw # XXX
248 # DEPRECATED #from myslice.viewutils import the_user
250 # DEPRECATED #from django.template.loader import render_to_string
251 # DEPRECATED #from django.template import RequestContext
252 # DEPRECATED #from django.views import generic
254 # DEPRECATED #from django.contrib.formtools.wizard.views import NamedUrlSessionWizardView
255 # DEPRECATED ##from django.core.files.storage import FileSystemStorage
256 # DEPRECATED #from django.core.files.storage import default_storage
258 # DEPRECATED ##class MerlinWizard(NamedUrlSessionWizardView):
263 # DEPRECATED ## @classonlymethod
264 # DEPRECATED ## def as_view(cls, *args, **kwargs):
265 # DEPRECATED ## kwargs.update({
266 # DEPRECATED ## 'form_list': [
267 # DEPRECATED ## NameForm,
268 # DEPRECATED ## QuestForm,
269 # DEPRECATED ## ColorForm,
271 # DEPRECATED ## 'url_name': 'merlin_wizard'
273 # DEPRECATED ## return super(MerlinWizard, cls).as_view(*args, **kwargs)
275 # DEPRECATED #class UserRegisterWizardView(NamedUrlSessionWizardView):
276 # DEPRECATED ##class UserRegisterWizardView(LoginRequiredMixin, NamedUrlSessionWizardView):
277 # DEPRECATED # # Notice that I specify a file storage instance. If you don't specify this,
278 # DEPRECATED # # and you need to support FileField or ImageField in your forms, you'll get
279 # DEPRECATED # # errors from Django. This is something else I think could be handled by
280 # DEPRECATED # # the views better. Seems to me that it should just use whatever the
281 # DEPRECATED # # default/specified storage is for the rest of your project/application.
282 # DEPRECATED # file_storage = default_storage # FileSystemStorage()
283 # DEPRECATED # template_name = "register_user_wizard.html"
285 # DEPRECATED # def done(self, form_list, **kwargs):
286 # DEPRECATED # step1_form = form_list[0]
287 # DEPRECATED # step2_form = form_list[1]
289 # DEPRECATED # productext = self.create_product(product_form)
290 # DEPRECATED # shippings = self.create_shippings(productext, shipping_forms)
291 # DEPRECATED # images = self.create_images(productext, image_forms)
293 # DEPRECATED # if all([productext, shippings, images]):
294 # DEPRECATED # del self.request.session["wizard_product_wizard_view"]
296 # DEPRECATED # messages.success(self.request,
297 # DEPRECATED # _("Your product has been created."))
298 # DEPRECATED # return HttpResponseRedirect(self.get_success_url(productext))
300 # DEPRECATED # messages.error(self.request, _("Something went wrong creating your "
301 # DEPRECATED # "product. Please try again or contact support."))
302 # DEPRECATED # return HttpResponseRedirect(reverse("register_wizard"))
304 # DEPRECATED # #def get_form_kwargs(self, step):
305 # DEPRECATED # # if step == "product":
306 # DEPRECATED # # return {"user": self.request.user}
307 # DEPRECATED # # return {}
309 # DEPRECATED ## The portal should hook the slice and user creation pages
311 # DEPRECATED #def register_user(request):
313 # DEPRECATED # if request.method == 'POST':
314 # DEPRECATED # form = UserRegisterForm(request.POST) # Nous reprenons les données
315 # DEPRECATED # if form.is_valid():
316 # DEPRECATED # first_name = form.cleaned_data['first_name']
317 # DEPRECATED # last_name = form.cleaned_data['last_name']
318 # DEPRECATED # email = form.cleaned_data['email']
319 # DEPRECATED # password = form.cleaned_data['password']
320 # DEPRECATED # password2 = form.cleaned_data['password2']
321 # DEPRECATED # keypair = form.cleaned_data['keypair']
322 # DEPRECATED # ## Ici nous pouvons traiter les données du formulaire
323 # DEPRECATED # #sujet = form.cleaned_data['sujet']
324 # DEPRECATED # #message = form.cleaned_data['message']
325 # DEPRECATED # #envoyeur = form.cleaned_data['envoyeur']
326 # DEPRECATED # #renvoi = form.cleaned_data['renvoi']
327 # DEPRECATED # ## Nous pourrions ici envoyer l'e-mail grâce aux données que nous venons de récupérer
328 # DEPRECATED # #envoi = True
330 # DEPRECATED # form = UserRegisterForm()
331 # DEPRECATED # return render(request, 'register_user.html', locals())
333 # DEPRECATED #def index(request):
335 # DEPRECATED # WIZARD_TITLE = 'User registration'
336 # DEPRECATED # STEP1_TITLE = 'Enter your details'
337 # DEPRECATED # STEP2_TITLE = 'Select your institution'
338 # DEPRECATED # STEP3_TITLE = 'Authentication'
339 # DEPRECATED # STEP4_TITLE = 'Request a slice (optional)'
340 # DEPRECATED # STEP5_TITLE = 'Waiting for validation'
341 # DEPRECATED # STEP6_TITLE = 'Account validated'
343 # DEPRECATED # STEP0 = render_to_string('account_validated.html', context_instance=RequestContext(request))
344 # DEPRECATED # STEP2_HTML = """
345 # DEPRECATED # coucou
347 # DEPRECATED # STEP4 = """
350 # DEPRECATED # STEP5 = render_to_string('account_validated.html', context_instance=RequestContext(request))
352 # DEPRECATED # p = PortalPage(request)
354 # DEPRECATED # # This is redundant with the Wizard title
355 # DEPRECATED # p << "<h3>User registration</h3>"
357 # DEPRECATED # sons = []
358 # DEPRECATED # start_step = 1
360 # DEPRECATED # # STEP 1
361 # DEPRECATED # # If the user already exists (is logged), let's display a summary of his account details
362 # DEPRECATED # # Otherwise propose a form to fill in
363 # DEPRECATED # if the_user(request):
364 # DEPRECATED # # Fill a disabled form with user info
365 # DEPRECATED # # Please logout to register another user
366 # DEPRECATED # sons.append(Raw(page=p, title=STEP1_TITLE, togglable=False, html=STEP0))
367 # DEPRECATED # start_step += 1
369 # DEPRECATED # # We could pass a list of fields also, instead of retrieving them from metadata
370 # DEPRECATED # # Otherwise we need some heuristics to display nice forms
371 # DEPRECATED # # XXX Could we log the user in after the form is validated ?
372 # DEPRECATED # # XXX Explain the password is for XXX
373 # DEPRECATED # field_list = [{
374 # DEPRECATED # 'name' : 'First name',
375 # DEPRECATED # 'field' : 'firstname',
376 # DEPRECATED # 'type' : 'text',
377 # DEPRECATED # 'validate_rx' : '^[a-zA-Z -]+$',
378 # DEPRECATED # 'validate_err': 'Your first name must be comprised of letters only',
379 # DEPRECATED # 'description' : 'Enter your first name',
381 # DEPRECATED # 'name' : 'Last name',
382 # DEPRECATED # 'field' : 'lastname',
383 # DEPRECATED # 'type' : 'text',
384 # DEPRECATED # 'validate_rx' : '^[a-zA-Z -]+$',
385 # DEPRECATED # 'validate_err': 'Your last name must be comprised of letters only',
386 # DEPRECATED # 'description' : 'Enter your last name',
388 # DEPRECATED # 'name' : 'Email',
389 # DEPRECATED # 'field' : 'email',
390 # DEPRECATED # 'type' : 'text',
391 # DEPRECATED # 'description' : 'Enter your email address',
393 # DEPRECATED # 'name' : 'Password',
394 # DEPRECATED # 'field' : 'password',
395 # DEPRECATED # 'type' : 'password',
396 # DEPRECATED # 'description' : 'Enter your password',
398 # DEPRECATED # 'name' : 'Confirm password',
399 # DEPRECATED # 'field' : 'password2',
400 # DEPRECATED # 'type' : 'password',
401 # DEPRECATED # 'description' : 'Enter your password again',
403 # DEPRECATED # sons.append(CreateForm(page = p, title = STEP1_TITLE, togglable = False, object = 'local:user', fields = field_list))
405 # DEPRECATED # # STEP 2
406 # DEPRECATED # # If the user already exists (is logged), let's display a summary of its institution
407 # DEPRECATED # # Otherwise propose a form to fill in (we should base our selection on the email)
408 # DEPRECATED # if the_user(request):
409 # DEPRECATED # # Fill a disabled form with institution
410 # DEPRECATED # # Please logout to register another user
411 # DEPRECATED # sons.append(Raw(page=p, title=STEP2_TITLE, togglable=False, html="User created"))
412 # DEPRECATED # start_step += 1
414 # DEPRECATED # sons.append(CreateForm(page = p, title = STEP2_TITLE, togglable = False, object = 'slice')) #institution'))
416 # DEPRECATED # # STEP3
417 # DEPRECATED # # Please should your prefered authentication method
418 # DEPRECATED # # This step should allow the user to either choose the user or managed mode in MySlice
419 # DEPRECATED # sons.append(Raw(page = p, title = STEP3_TITLE, togglable = False, html = STEP2_HTML))
421 # DEPRECATED # # Step 4: Request a slice (optional)
422 # DEPRECATED # sons.append(CreateForm(page = p, title = STEP4_TITLE, togglable = False, object = 'slice'))
424 # DEPRECATED # # Step 5: Your request is waiting for validation
425 # DEPRECATED # # Periodic refresh
426 # DEPRECATED # sons.append(Raw(page = p, title = STEP5_TITLE, togglable = False, html = STEP4))
428 # DEPRECATED # # Step 6: Account validation = welcome for newly validated users
429 # DEPRECATED # # . delegation
430 # DEPRECATED # # . platforms
431 # DEPRECATED # # . slice
432 # DEPRECATED # # . pointers
433 # DEPRECATED # sons.append(Raw(page = p, title = STEP6_TITLE, togglable = False, html = STEP5))
435 # DEPRECATED # wizard = Wizard(
436 # DEPRECATED # page = p,
437 # DEPRECATED # title = WIZARD_TITLE,
438 # DEPRECATED # togglable = False,
439 # DEPRECATED # sons = sons,
440 # DEPRECATED # start_step = start_step,
443 # DEPRECATED # p << wizard.render(request) # in portal page if possible
445 # DEPRECATED # return p.render()
448 # DEPRECATED ## view for my_account
449 # DEPRECATED # class MyAccountView(TemplateView):
450 # DEPRECATED # template_name = "my_account.html"
452 # DEPRECATED # def from_process(self, request, **cleaned_data):
453 # DEPRECATED # #if request.method == 'POST':
454 # DEPRECATED # # if request.POST['submit_name']:
455 # DEPRECATED # if 'fname' in request.POST:
456 # DEPRECATED # messsag= "Got Name"
457 # DEPRECATED # #return render(request, 'portal/my_account.html')
458 # DEPRECATED # #response = HttpResponse("Here's the text of the Web page.")
459 # DEPRECATED # return HttpResponse(message)
461 # DEPRECATED # def get_context_data(self, **kwargs):
462 # DEPRECATED # page = Page(self.request)
463 # DEPRECATED # context = super(MyAccountView, self).get_context_data(**kwargs)
464 # DEPRECATED # context['person'] = self.request.user
465 # DEPRECATED # # XXX This is repeated in all pages
466 # DEPRECATED # # more general variables expected in the template
467 # DEPRECATED # context['title'] = 'User Profile Page'
468 # DEPRECATED # # the menu items on the top
469 # DEPRECATED # context['topmenu_items'] = topmenu_items('my_account', self.request)
470 # DEPRECATED # # so we can sho who is logged
471 # DEPRECATED # context['username'] = the_user(self.request)
472 # DEPRECATED # context.update(page.prelude_env())
473 # DEPRECATED # return context
477 # View for my_account form
478 def my_account(request):
479 return render(request, 'my_account.html', {
481 'topmenu_items': topmenu_items('My Account', request),
482 'username': the_user (request)
486 class PlatformsView(TemplateView):
487 template_name = "platforms.html"
489 def get_context_data(self, **kwargs):
490 page = Page(self.request)
492 network_query = Query().get('local:platform').filter_by('disabled', '==', '0').select('platform','platform_longname','gateway_type')
493 page.enqueue_query(network_query)
495 page.expose_js_metadata()
496 page.expose_queries()
497 networklist = Hazelnut(
500 domid = 'checkboxes',
501 # this is the query at the core of the slice list
502 query = network_query,
503 query_all = network_query,
505 datatables_options = {
506 # for now we turn off sorting on the checkboxes columns this way
507 # this of course should be automatic in hazelnut
508 'aoColumns' : [None, None, None, None, {'bSortable': False}],
509 'iDisplayLength' : 25,
510 'bLengthChange' : True,
514 # networklist = SimpleList(
518 # query = network_query,
521 context = super(PlatformsView, self).get_context_data(**kwargs)
522 context['person'] = self.request.user
523 context['networks'] = networklist.render(self.request)
525 # XXX This is repeated in all pages
526 # more general variables expected in the template
527 context['title'] = 'Platforms connected to MySlice'
528 # the menu items on the top
529 context['topmenu_items'] = topmenu_items('Platforms', self.request)
530 # so we can sho who is logged
531 context['username'] = the_user(self.request)
533 context.update(page.prelude_env())
537 #my_acc form value processing
538 def acc_process(request):
539 # getting the user_id from the session [now hardcoded]
540 get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
541 if 'submit_name' in request.POST:
542 edited_first_name = request.POST['fname']
543 edited_last_name = request.POST['lname']
544 #email = 'test_email@gmail.com'
545 #password = 'test_pp'
546 #message = 'F_Name: %s L_name: %s dummy_pp: %s' % (first_name, last_name, password)
549 # insert into DB [needed for registration page]
550 #approach borrowed from register view
551 #new_user = PendingUser.objects.create_inactive_user(edited_first_name, edited_last_name, email, password, site)
552 #conventional approach
553 #b = PendingUser(first_name=edited_first_name, last_name=edited_last_name)
556 # select and update [will be used throughout this view]
557 # select the logged in user [for the moment hard coded]
558 #get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
559 # update first and last name
560 get_user.first_name = edited_first_name
561 get_user.last_name = edited_last_name
564 return HttpResponse('Success: Name Updated!!')
565 elif 'submit_pass' in request.POST:
566 edited_password = request.POST['password']
567 # select the logged in user [for the moment hard coded]
568 #get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
570 get_user.password = edited_password
572 return HttpResponse('Success: Password Changed!!')
573 elif 'generate' in request.POST:
575 #from M2Crypto import Rand, RSA, BIO
579 def blank_callback():
580 "Replace the default dashes"
584 Rand.rand_seed (os.urandom (KEY_LENGTH))
586 key = RSA.gen_key (KEY_LENGTH, 65537, blank_callback)
587 # Create memory buffers
588 pri_mem = BIO.MemoryBuffer()
589 pub_mem = BIO.MemoryBuffer()
590 # Save keys to buffers
591 key.save_key_bio(pri_mem, None)
592 key.save_pub_key_bio(pub_mem)
595 public_key = pub_mem.getvalue()
596 private_key = pri_mem.getvalue()
598 keypair = '{"user_public_key":"'+ public_key + '", "user_private_key":"'+ private_key + '"}'
599 keypair = re.sub("\r", "", keypair)
600 keypair = re.sub("\n", "\\n", keypair)
601 #keypair = keypair.rstrip('\r\n')
602 keypair = ''.join(keypair.split())
603 get_user.keypair = keypair
605 return HttpResponse('Success: New Keypair Generated! %s' % keypair)
607 elif 'upload_key' in request.POST:
608 up_file = request.FILES['pubkey']
609 file_content = up_file.read()
610 file_name = up_file.name
611 file_extension = os.path.splitext(file_name)[1]
612 allowed_extension = ['.pub','.txt']
613 if file_extension in allowed_extension and re.search(r'ssh-rsa',file_content):
614 file_content = '{"user_public_key":"'+ file_content +'"}'
615 file_content = re.sub("\r", "", file_content)
616 file_content = re.sub("\n", "\\n",file_content)
617 file_content = ''.join(file_content.split())
618 get_user.keypair = file_content
620 return HttpResponse('Success: Publickey uploaded! Old records overwritten')
622 return HttpResponse('Please upload a valid RSA public key [.txt or .pub].')
625 message = 'You submitted an empty form.'
626 return HttpResponse(message)
628 def register_4m_f4f(request):
630 if request.method == 'POST':
631 #get_email = PendingUser.objects.get(email)
632 reg_fname = request.POST.get('firstname', '')
633 reg_lname = request.POST.get('lastname', '')
634 reg_aff = request.POST.get('affiliation','')
635 reg_email = request.POST.get('email','').lower()
637 #POST value validation
638 if (re.search(r'^[\w+\s.@+-]+$', reg_fname)==None):
639 errors.append('First Name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
640 #return HttpResponse("Only Letters, Numbers, - and _ allowd in First Name")
641 #return render(request, 'register_4m_f4f.html')
642 if (re.search(r'^[\w+\s.@+-]+$', reg_lname) == None):
643 errors.append('Last Name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
644 #return HttpResponse("Only Letters, Numbers, - and _ is allowed in Last name")
645 #return render(request, 'register_4m_f4f.html')
646 if (re.search(r'^[\w+\s.@+-]+$', reg_aff) == None):
647 errors.append('Affiliation may contain only letters, numbers, spaces and @/./+/-/_ characters.')
648 #return HttpResponse("Only Letters, Numbers and _ is allowed in Affiliation")
649 #return render(request, 'register_4m_f4f.html')
650 if PendingUser.objects.filter(email__iexact=reg_email):
651 errors.append('Email already registered.Please provide a new email address.')
652 #return HttpResponse("Email Already exists")
653 #return render(request, 'register_4m_f4f.html')
654 if 'generate' in request.POST['question']:
656 #from M2Crypto import Rand, RSA, BIO
660 def blank_callback():
661 "Replace the default dashes"
665 Rand.rand_seed (os.urandom (KEY_LENGTH))
667 key = RSA.gen_key (KEY_LENGTH, 65537, blank_callback)
668 # Create memory buffers
669 pri_mem = BIO.MemoryBuffer()
670 pub_mem = BIO.MemoryBuffer()
671 # Save keys to buffers
672 key.save_key_bio(pri_mem, None)
673 key.save_pub_key_bio(pub_mem)
675 public_key = pub_mem.getvalue()
676 private_key = pri_mem.getvalue()
678 keypair = '{"user_public_key":"'+ public_key + '", "user_private_key":"'+ private_key + '"}'
679 keypair = re.sub("\r", "", keypair)
680 keypair = re.sub("\n", "\\n", keypair)
681 #keypair = keypair.rstrip('\r\n')
682 keypair = ''.join(keypair.split())
683 #return HttpResponse(keypair)
685 up_file = request.FILES['user_public_key']
686 file_content = up_file.read()
687 file_name = up_file.name
688 file_extension = os.path.splitext(file_name)[1]
689 allowed_extension = ['.pub','.txt']
690 if file_extension in allowed_extension and re.search(r'ssh-rsa',file_content):
691 keypair = '{"user_public_key":"'+ file_content +'"}'
692 keypair = re.sub("\r", "", keypair)
693 keypair = re.sub("\n", "\\n",keypair)
694 keypair = ''.join(keypair.split())
696 errors.append('Please upload a valid RSA public key [.txt or .pub].')
698 #b = PendingUser(first_name=reg_fname, last_name=reg_lname, affiliation=reg_aff,
699 # email=reg_email, password=request.POST['password'], keypair=keypair)
702 b = PendingUser(first_name=reg_fname, last_name=reg_lname, affiliation=reg_aff,
703 email=reg_email, password=request.POST['password'], keypair=keypair)
705 return render(request, 'user_register_complete.html')
707 return render(request, 'register_4m_f4f.html',{
708 'topmenu_items': topmenu_items('Register', request),
710 'firstname': request.POST.get('firstname', ''),
711 'lastname': request.POST.get('lastname', ''),
712 'affiliation': request.POST.get('affiliation', ''),
713 'email': request.POST.get('email', ''),
714 'password': request.POST.get('password', ''),
718 # view for contact form
719 def contact(request):
720 if request.method == 'POST': # If the form has been submitted...
721 form = ContactForm(request.POST) # A form bound to the POST data
722 if form.is_valid(): # All validation rules pass
723 # Process the data in form.cleaned_data
724 first_name = form.cleaned_data['first_name']
725 last_name = form.cleaned_data['last_name']
726 affiliation = form.cleaned_data['affiliation']
727 subject = form.cleaned_data['subject']
728 message = form.cleaned_data['message']
729 email = form.cleaned_data['email'] # email of the sender
730 cc_myself = form.cleaned_data['cc_myself']
732 recipients = ['yasin.upmc@gmail.com']
734 recipients.append(email)
736 from django.core.mail import send_mail
737 send_mail("Onelab user submitted a query ", [first_name,last_name,affiliation,subject,message], email, recipients)
738 return render(request,'contact_sent.html') # Redirect after POST
740 form = ContactForm() # An unbound form
742 return render(request, 'contact.html', {
744 'topmenu_items': topmenu_items('Contact Us', request),
745 'username': the_user (request)
750 def slice_request(request):
751 if request.method == 'POST': # If the form has been submitted...
752 form = SliceRequestForm(request.POST) # A form bound to the POST data
753 if form.is_valid(): # All validation rules pass
754 # Process the data in form.cleaned_data
755 slice_name = form.cleaned_data['slice_name']
756 number_of_nodes = form.cleaned_data['number_of_nodes']
757 type_of_nodes = form.cleaned_data['type_of_nodes']
758 purpose = form.cleaned_data['purpose']
759 email = form.cleaned_data['email'] # email of the sender
760 cc_myself = form.cleaned_data['cc_myself']
762 recipients = ['yasin.upmc@gmail.com','jordan.auge@lip6.fr']
764 recipients.append(email)
766 from django.core.mail import send_mail
767 send_mail("Onelab New Slice request form submitted", [slice_name,number_of_nodes,type_of_nodes,purpose], email, recipients)
768 return render(request,'slicereq_recvd.html') # Redirect after POST
770 form = SliceRequestForm() # An unbound form
773 # template_env['form'] = form
774 # template_env['topmenu_items'] = topmenu_items('Request a slice', request)
775 # template_env['unfold1_main'] = render(request, 'slice_request_.html', {
778 # from django.shortcuts import render_to_response
779 # from django.template import RequestContext
780 # return render_to_response ('view-unfold1.html',template_env,
781 # context_instance=RequestContext(request))
783 return render(request, 'slice_request.html', {
785 'topmenu_items': topmenu_items('Request a slice', request),
786 'username': the_user (request)
790 class PresViewView(TemplateView):
791 template_name = "view-unfold1.html"
793 def get_context_data(self, **kwargs):
795 page = Page(self.request)
797 pres_view = PresView(page = page)
799 context = super(PresViewView, self).get_context_data(**kwargs)
801 #context['ALL_STATIC'] = "all_static"
802 context['unfold1_main'] = pres_view.render(self.request)
804 # XXX This is repeated in all pages
805 # more general variables expected in the template
806 context['title'] = 'Test view that combines various plugins'
807 # the menu items on the top
808 context['topmenu_items'] = topmenu_items('PresView', self.request)
809 # so we can sho who is logged
810 context['username'] = the_user(self.request)
812 prelude_env = page.prelude_env()
813 context.update(prelude_env)
817 def json_me(config_file,type):
819 for ligne in config_file:
820 if not ligne.startswith('#'):
821 args = ligne.split(';')
822 json_answer += str('{ "name": "' + args[0] + '" ,"id":"' + args[1] + '" ,"descriptif":"' + args[2]+'"')
824 json_answer += str(',"contraints":')
826 json_answer += str('""')
828 json_answer += str(args[3])
829 json_answer += str('},')
830 return json_answer[:-1]
833 DIR = '/var/myslice/'
834 STATIC = '%s/config_method_static' % DIR
835 DYNAMIC = '%s/config_method_dynamic' % DIR
836 ANIMATION = '%s/config_method_animation' % DIR
838 def pres_view_methods(request, type):
842 elif type =="static":
843 config = open(STATIC, "r")
844 json_answer = str('{ "options": [')
845 json_answer += str(json_me(config,"static"))
846 json_answer += str('] }')
848 elif type =="dynamic":
849 config = open(DYNAMIC, "r")
850 json_answer = str('{ "options": [')
851 json_answer += str(json_me(config,"dynamic"))
852 json_answer += str('] }')
854 elif type =="animation":
855 config = open(ANIMATION, "r")
856 json_answer = str('{ "options": [')
857 json_answer += str(json_me(config,"animation"))
858 json_answer += str('] }')
861 config = open(STATIC, "r")
862 json_answer = str('{ "static": [')
863 json_answer += str(json_me(config,"static"))
864 json_answer += str('],')
865 json_answer += str('"dynamic": [')
867 config = open(DYNAMIC, "r")
868 json_answer += str(json_me(config,"dynamic"))
869 json_answer += str('],')
870 json_answer += str('"animation": [')
872 config = open(ANIMATION, "r")
873 json_answer += str(json_me(config,"animation"))
874 json_answer += str('] }')
878 return HttpResponse (json_answer, mimetype="application/json")
880 def pres_view_animation(request, constraints, id):
882 # sites crees depuis 2008
883 # static.py?contraints=']date_created':1262325600&id='name_id"'
885 # method = request.getvalue('method') #ex : GetSites
886 #constraints = "']date_created':1262325600"
892 # method = 'GetSites'#request.getvalue('method') #ex : GetSites
893 # constraints = {}#request.getvalue('constraints') // nul = {}
894 # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
896 config_file = open(ANIMATION, "r")
897 for ligne in config_file:
898 if not ligne.startswith('#'):
899 ligne = ligne.split('\n')
900 first = ligne[0].split(';')
901 if (str(first[1]) == str(id)):
905 #Les print_method, print_option sont definis par le client (js)
906 #Les animations acceptent que les connexions anonymous
907 # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
908 args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
911 #Creation d'un objet event
915 "print_options": event.print_options,
916 "print_method": event.print_method,
917 "message": event.data
922 json_answer = json.dumps(cmd)
923 return HttpResponse (json_answer, mimetype="application/json")
925 def pres_view_static(request, constraints, id):
926 #constraints = "']date_created':1262325600"
929 # method = 'GetSites'#request.getvalue('method') #ex : GetSites
930 # constraints = {}#request.getvalue('constraints') // nul = {}
931 # response_field = "'site_id','name','date_created'"#request.getvalue('response_field')
933 config_file = open(STATIC, "r")
934 for ligne in config_file:
935 if not ligne.startswith('#'):
936 ligne = ligne.split('\n')
937 first = ligne[0].split(';')
938 if (str(first[1]) == str(id)):
942 #Les print_method, print_option sont definis par le client (js)
943 #Les animations acceptent que les connexions anonymous
944 # args = "postmsg;animation;;;anonymous;https://www.planet-lab.eu/PLCAPI/;"
945 args = ";;"+str(save[8])+";"+str(save[9])+";anonymous;"+str(save[5])+";"+str(save[6])+";{"+str(constraints)+"};"+str(save[7])+";"
948 #Creation d'un objet event
952 "print_options": event.print_options,
953 "print_method": event.print_method,
954 "message": event.data
959 json_answer = json.dumps(cmd)
960 return HttpResponse (json_answer, mimetype="application/json")
962 class ValidatePendingView(TemplateView):
963 template_name = "validate_pending.html"
965 def get_context_data(self, **kwargs):
966 # We might have slices on different registries with different user accounts
967 # 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
968 # Different registries mean different identities, unless we identify via SFA HRN or have associated the user email to a single hrn
970 #messages.info(self.request, 'You have logged in')
971 page = Page(self.request)
973 ctx_my_authorities = {}
974 ctx_delegation_authorities = {}
977 # The user need to be logged in
978 if the_user(self.request):
979 # Who can a PI validate:
980 # His own authorities + those he has credentials for.
981 # In MySlice we need to look at credentials also.
984 # XXX This will have to be asynchroneous. Need to implement barriers,
985 # for now it will be sufficient to have it working statically
987 # get user_id to later on query accounts
988 # XXX Having real query plan on local tables would simplify all this
989 # XXX $user_email is still not available for local tables
990 #user_query = Query().get('local:user').filter_by('email', '==', '$user_email').select('user_id')
991 user_query = Query().get('local:user').filter_by('email', '==', the_user(self.request)).select('user_id')
992 user, = execute_query(self.request, user_query)
993 user_id = user['user_id']
995 # Query manifold to learn about available SFA platforms for more information
996 # In general we will at least have the portal
997 # For now we are considering all registries
1000 sfa_platforms_query = Query().get('local:platform').filter_by('gateway_type', '==', 'sfa').select('platform_id', 'platform', 'auth_type')
1001 sfa_platforms = execute_query(self.request, sfa_platforms_query)
1002 for sfa_platform in sfa_platforms:
1003 print "SFA PLATFORM > ", sfa_platform['platform']
1004 if not 'auth_type' in sfa_platform:
1006 auth = sfa_platform['auth_type']
1007 if not auth in all_authorities:
1008 all_authorities.append(auth)
1009 platform_ids.append(sfa_platform['platform_id'])
1011 # We can check on which the user has authoritity credentials = PI rights
1012 credential_authorities = set()
1013 credential_authorities_expired = set()
1015 # User account on these registries
1016 user_accounts_query = Query.get('local:account').filter_by('user_id', '==', user_id).filter_by('platform_id', 'included', platform_ids).select('config')
1017 user_accounts = execute_query(self.request, user_accounts_query)
1019 #print user_accounts
1021 for user_account in user_accounts:
1022 config = json.loads(user_account['config'])
1024 if 'authority_credentials' in config:
1025 for authority_hrn, credential in config['authority_credentials'].items():
1026 #if credential is not expired:
1027 credential_authorities.add(authority_hrn)
1029 # credential_authorities_expired.add(authority_hrn)
1030 if 'delegated_authority_credentials' in config:
1031 for authority_hrn, credential in config['delegated_authority_credentials'].items():
1032 #if credential is not expired:
1033 credential_authorities.add(authority_hrn)
1035 # credential_authorities_expired.add(authority_hrn)
1037 print 'credential_authorities =', credential_authorities
1038 print 'credential_authorities_expired =', credential_authorities_expired
1040 # ** Where am I a PI **
1041 # For this we need to ask SFA (of all authorities) = PI function
1042 pi_authorities_query = Query.get('user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
1043 pi_authorities_tmp = execute_query(self.request, pi_authorities_query)
1044 pi_authorities = set()
1045 for pa in pi_authorities_tmp:
1046 pi_authorities |= set(pa['pi_authorities'])
1048 print "pi_authorities =", pi_authorities
1050 # My authorities + I have a credential
1051 pi_credential_authorities = pi_authorities & credential_authorities
1052 pi_no_credential_authorities = pi_authorities - credential_authorities - credential_authorities_expired
1053 pi_expired_credential_authorities = pi_authorities & credential_authorities_expired
1054 # Authorities I've been delegated PI rights
1055 pi_delegation_credential_authorities = credential_authorities - pi_authorities
1056 pi_delegation_expired_authorities = credential_authorities_expired - pi_authorities
1058 print "pi_credential_authorities =", pi_credential_authorities
1059 print "pi_no_credential_authorities =", pi_no_credential_authorities
1060 print "pi_expired_credential_authorities =", pi_expired_credential_authorities
1061 print "pi_delegation_credential_authorities = ", pi_delegation_credential_authorities
1062 print "pi_delegation_expired_authorities = ", pi_delegation_expired_authorities
1064 # Summary intermediary
1065 pi_my_authorities = pi_credential_authorities | pi_no_credential_authorities | pi_expired_credential_authorities
1066 pi_delegation_authorities = pi_delegation_credential_authorities | pi_delegation_expired_authorities
1069 print "pi_my_authorities = ", pi_my_authorities
1070 print "pi_delegation_authorities = ", pi_delegation_authorities
1073 queried_pending_authorities = pi_my_authorities | pi_delegation_authorities
1075 print "queried_pending_authorities = ", queried_pending_authorities
1077 # Pending requests + authorities
1078 #pending_users = PendingUser.objects.filter(authority_hrn__in = queried_pending_authorities).all()
1079 #pending_slices = PendingSlice.objects.filter(authority_hrn__in = queried_pending_authorities).all()
1080 pending_users = PendingUser.objects.all()
1081 pending_slices = PendingSlice.objects.all()
1083 # Dispatch requests and build the proper structure for the template:
1085 print "pending users =", pending_users
1086 print "pending slices =", pending_slices
1088 for user in pending_users:
1089 auth_hrn = user.authority_hrn
1091 auth_hrn = "ple.upmc" # XXX HARDCODED
1094 request['type'] = 'user'
1095 request['id'] = 'TODO' # XXX in DB ?
1096 request['timestamp'] = 'TODO' # XXX in DB ?
1097 request['details'] = "%s %s <%s>" % (user.first_name, user.last_name, user.email)
1099 if auth_hrn in pi_my_authorities:
1100 dest = ctx_my_authorities
1102 # define the css class
1103 if auth_hrn in pi_credential_authorities:
1104 request['allowed'] = 'allowed'
1105 elif auth_hrn in pi_expired_credential_authorities:
1106 request['allowed'] = 'expired'
1107 else: # pi_no_credential_authorities
1108 request['allowed'] = 'denied'
1110 elif auth_hrn in pi_delegation_authorities:
1111 dest = ctx_delegation_authorities
1113 if auth_hrn in pi_delegation_credential_authorities:
1114 request['allowed'] = 'allowed'
1115 else: # pi_delegation_expired_authorities
1116 request['allowed'] = 'expired'
1121 if not auth_hrn in dest:
1123 print "auth_hrn [%s] was added %r" % (auth_hrn, request)
1124 dest[auth_hrn].append(request)
1126 for slice in pending_slices:
1127 auth_hrn = slice.authority_hrn
1129 auth_hrn = "ple.upmc" # XXX HARDCODED
1132 request['type'] = 'slice'
1133 request['id'] = 'TODO' # XXX in DB ?
1134 request['timestamp'] = 'TODO' # XXX in DB ?
1135 request['details'] = "Number of nodes: %d -- Type of nodes: %s<br/>%s" % ('TODO', 'TODO', 'TODO') # XXX
1136 if auth_hrn in pi_my_authorities:
1137 dest = ctx_my_authorities
1139 # define the css class
1140 if auth_hrn in pi_credential_authorities:
1141 request['allowed'] = 'allowed'
1142 elif auth_hrn in pi_expired_credential_authorities:
1143 request['allowed'] = 'expired'
1144 else: # pi_no_credential_authorities
1145 request['allowed'] = 'denied'
1147 elif auth_hrn in pi_delegation_authorities:
1148 dest = ctx_delegation_authorities
1150 if auth_hrn in pi_delegation_credential_authorities:
1151 request['allowed'] = 'allowed'
1152 else: # pi_delegation_expired_authorities
1153 request['allowed'] = 'expired'
1155 if not auth_hrn in dest:
1157 dest[auth_hrn].append(request)
1159 context = super(ValidatePendingView, self).get_context_data(**kwargs)
1160 context['my_authorities'] = ctx_my_authorities
1161 context['delegation_authorities'] = ctx_delegation_authorities
1163 # XXX This is repeated in all pages
1164 # more general variables expected in the template
1165 context['title'] = 'Test view that combines various plugins'
1166 # the menu items on the top
1167 context['topmenu_items'] = topmenu_items('Dashboard', self.request)
1168 # so we can sho who is logged
1169 context['username'] = the_user(self.request)
1171 # XXX We need to prepare the page for queries
1172 #context.update(page.prelude_env())