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 plugins.lists.simplelist import SimpleList
31 from portal import signals
32 from portal.forms import UserRegisterForm, SliceRequestForm, ContactForm
33 from portal.util import RegistrationView, ActivationView
34 from portal.models import PendingUser, PendingSlice
35 from manifold.core.query import Query
36 from unfold.page import Page
37 from myslice.viewutils import topmenu_items, the_user
38 from django.http import HttpResponseRedirect, HttpResponse
41 class DashboardView(TemplateView):
42 template_name = "dashboard.html"
44 def get_context_data(self, **kwargs):
45 user_hrn = 'ple.upmc.jordan_auge'
47 #messages.info(self.request, 'You have logged in')
48 page = Page(self.request)
51 #slice_query = Query().get('slice').filter_by('user.user_hrn', 'contains', user_hrn).select('slice_hrn')
52 slice_query = Query().get('user').filter_by('user_hrn', '==', user_hrn).select('user_hrn', 'slice.slice_hrn')
53 auth_query = Query().get('network').select('network_hrn')
54 page.enqueue_query(slice_query)
55 page.enqueue_query(auth_query)
59 slicelist = SimpleList(
62 key = 'slice.slice_hrn',
66 authlist = SimpleList(
73 context = super(DashboardView, self).get_context_data(**kwargs)
74 context['person'] = self.request.user
75 context['networks'] = authlist.render(self.request)
76 context['slices'] = slicelist.render(self.request)
78 # XXX This is repeated in all pages
79 # more general variables expected in the template
80 context['title'] = 'Test view that combines various plugins'
81 # the menu items on the top
82 context['topmenu_items'] = topmenu_items('Dashboard', self.request)
83 # so we can sho who is logged
84 context['username'] = the_user(self.request)
86 context.update(page.prelude_env())
90 class UserRegisterView(RegistrationView):
92 A registration backend which follows a simple workflow:
94 1. User signs up, inactive account is created.
96 2. Email is sent to user with activation link.
98 3. User clicks activation link, account is now active.
100 Using this backend requires that
102 * ``registration`` be listed in the ``INSTALLED_APPS`` setting
103 (since this backend makes use of models defined in this
106 * The setting ``ACCOUNT_ACTIVATION_DAYS`` be supplied, specifying
107 (as an integer) the number of days from registration during
108 which a user may activate their account (after that period
109 expires, activation will be disallowed).
111 * The creation of the templates
112 ``registration/activation_email_subject.txt`` and
113 ``registration/activation_email.txt``, which will be used for
114 the activation email. See the notes for this backends
115 ``register`` method for details regarding these templates.
117 Additionally, registration can be temporarily closed by adding the
118 setting ``REGISTRATION_OPEN`` and setting it to
119 ``False``. Omitting this setting, or setting it to ``True``, will
120 be interpreted as meaning that registration is currently open and
123 Internally, this is accomplished via storing an activation key in
124 an instance of ``registration.models.RegistrationProfile``. See
125 that model and its custom manager for full documentation of its
126 fields and supported operations.
129 form_class = UserRegisterForm
131 def register(self, request, **cleaned_data):
133 Given a username, email address and password, register a new
134 user account, which will initially be inactive.
136 Along with the new ``User`` object, a new
137 ``registration.models.RegistrationProfile`` will be created,
138 tied to that ``User``, containing the activation key which
139 will be used for this account.
141 An email will be sent to the supplied email address; this
142 email should contain an activation link. The email will be
143 rendered using two templates. See the documentation for
144 ``RegistrationProfile.send_activation_email()`` for
145 information about these templates and the contexts provided to
148 After the ``User`` and ``RegistrationProfile`` are created and
149 the activation email is sent, the signal
150 ``registration.signals.user_registered`` will be sent, with
151 the new ``User`` as the keyword argument ``user`` and the
152 class of this backend as the sender.
155 first_name = cleaned_data['first_name']
156 last_name = cleaned_data['last_name']
157 affiliation= cleaned_data['affiliation']
158 email = cleaned_data['email']
159 password = cleaned_data['password1']
161 #password2 = cleaned_data['password2']
162 keypair = cleaned_data['keypair']
164 #if Site._meta.installed:
165 # site = Site.objects.get_current()
167 # site = RequestSite(request)
170 new_user = PendingUser.objects.create_inactive_user(first_name, last_name, email, password, site)
171 signals.user_registered.send(sender=self.__class__,
176 def get_context_data(self, **kwargs):
177 context = super(UserRegisterView, self).get_context_data(**kwargs)
178 context['topmenu_items'] = topmenu_items('Register', self.request)
179 context['username'] = the_user (self.request)
182 def registration_allowed(self, request):
184 Indicate whether account registration is currently permitted,
185 based on the value of the setting ``REGISTRATION_OPEN``. This
186 is determined as follows:
188 * If ``REGISTRATION_OPEN`` is not specified in settings, or is
189 set to ``True``, registration is permitted.
191 * If ``REGISTRATION_OPEN`` is both specified and set to
192 ``False``, registration is not permitted.
195 return getattr(settings, 'REGISTRATION_OPEN', True)
197 def get_success_url(self, request, user):
199 Return the name of the URL to redirect to after successful
203 return ('user_register_complete', (), {})
206 class UserValidateView(ActivationView):
207 def activate(self, request, activation_key):
209 Given an an activation key, look up and activate the user
210 account corresponding to that key (if possible).
212 After successful activation, the signal
213 ``registration.signals.user_activated`` will be sent, with the
214 newly activated ``User`` as the keyword argument ``user`` and
215 the class of this backend as the sender.
218 activated_user = RegistrationProfile.objects.activate_user(activation_key)
220 signals.user_activated.send(sender=self.__class__,
223 return activated_user
225 def get_success_url(self, request, user):
226 return ('registration_activation_complete', (), {})
229 # DEPRECATED #from portal.portalpage import PortalPage
230 # DEPRECATED #from plugins.wizard import Wizard
231 # DEPRECATED #from plugins.form import CreateForm
232 # DEPRECATED #from plugins.raw.raw import Raw # XXX
234 # DEPRECATED #from myslice.viewutils import the_user
236 # DEPRECATED #from django.template.loader import render_to_string
237 # DEPRECATED #from django.template import RequestContext
238 # DEPRECATED #from django.views import generic
240 # DEPRECATED #from django.contrib.formtools.wizard.views import NamedUrlSessionWizardView
241 # DEPRECATED ##from django.core.files.storage import FileSystemStorage
242 # DEPRECATED #from django.core.files.storage import default_storage
244 # DEPRECATED ##class MerlinWizard(NamedUrlSessionWizardView):
249 # DEPRECATED ## @classonlymethod
250 # DEPRECATED ## def as_view(cls, *args, **kwargs):
251 # DEPRECATED ## kwargs.update({
252 # DEPRECATED ## 'form_list': [
253 # DEPRECATED ## NameForm,
254 # DEPRECATED ## QuestForm,
255 # DEPRECATED ## ColorForm,
257 # DEPRECATED ## 'url_name': 'merlin_wizard'
259 # DEPRECATED ## return super(MerlinWizard, cls).as_view(*args, **kwargs)
261 # DEPRECATED #class UserRegisterWizardView(NamedUrlSessionWizardView):
262 # DEPRECATED ##class UserRegisterWizardView(LoginRequiredMixin, NamedUrlSessionWizardView):
263 # DEPRECATED # # Notice that I specify a file storage instance. If you don't specify this,
264 # DEPRECATED # # and you need to support FileField or ImageField in your forms, you'll get
265 # DEPRECATED # # errors from Django. This is something else I think could be handled by
266 # DEPRECATED # # the views better. Seems to me that it should just use whatever the
267 # DEPRECATED # # default/specified storage is for the rest of your project/application.
268 # DEPRECATED # file_storage = default_storage # FileSystemStorage()
269 # DEPRECATED # template_name = "register_user_wizard.html"
271 # DEPRECATED # def done(self, form_list, **kwargs):
272 # DEPRECATED # step1_form = form_list[0]
273 # DEPRECATED # step2_form = form_list[1]
275 # DEPRECATED # productext = self.create_product(product_form)
276 # DEPRECATED # shippings = self.create_shippings(productext, shipping_forms)
277 # DEPRECATED # images = self.create_images(productext, image_forms)
279 # DEPRECATED # if all([productext, shippings, images]):
280 # DEPRECATED # del self.request.session["wizard_product_wizard_view"]
282 # DEPRECATED # messages.success(self.request,
283 # DEPRECATED # _("Your product has been created."))
284 # DEPRECATED # return HttpResponseRedirect(self.get_success_url(productext))
286 # DEPRECATED # messages.error(self.request, _("Something went wrong creating your "
287 # DEPRECATED # "product. Please try again or contact support."))
288 # DEPRECATED # return HttpResponseRedirect(reverse("register_wizard"))
290 # DEPRECATED # #def get_form_kwargs(self, step):
291 # DEPRECATED # # if step == "product":
292 # DEPRECATED # # return {"user": self.request.user}
293 # DEPRECATED # # return {}
295 # DEPRECATED ## The portal should hook the slice and user creation pages
297 # DEPRECATED #def register_user(request):
299 # DEPRECATED # if request.method == 'POST':
300 # DEPRECATED # form = UserRegisterForm(request.POST) # Nous reprenons les données
301 # DEPRECATED # if form.is_valid():
302 # DEPRECATED # first_name = form.cleaned_data['first_name']
303 # DEPRECATED # last_name = form.cleaned_data['last_name']
304 # DEPRECATED # email = form.cleaned_data['email']
305 # DEPRECATED # password = form.cleaned_data['password']
306 # DEPRECATED # password2 = form.cleaned_data['password2']
307 # DEPRECATED # keypair = form.cleaned_data['keypair']
308 # DEPRECATED # ## Ici nous pouvons traiter les données du formulaire
309 # DEPRECATED # #sujet = form.cleaned_data['sujet']
310 # DEPRECATED # #message = form.cleaned_data['message']
311 # DEPRECATED # #envoyeur = form.cleaned_data['envoyeur']
312 # DEPRECATED # #renvoi = form.cleaned_data['renvoi']
313 # DEPRECATED # ## Nous pourrions ici envoyer l'e-mail grâce aux données que nous venons de récupérer
314 # DEPRECATED # #envoi = True
316 # DEPRECATED # form = UserRegisterForm()
317 # DEPRECATED # return render(request, 'register_user.html', locals())
319 # DEPRECATED #def index(request):
321 # DEPRECATED # WIZARD_TITLE = 'User registration'
322 # DEPRECATED # STEP1_TITLE = 'Enter your details'
323 # DEPRECATED # STEP2_TITLE = 'Select your institution'
324 # DEPRECATED # STEP3_TITLE = 'Authentication'
325 # DEPRECATED # STEP4_TITLE = 'Request a slice (optional)'
326 # DEPRECATED # STEP5_TITLE = 'Waiting for validation'
327 # DEPRECATED # STEP6_TITLE = 'Account validated'
329 # DEPRECATED # STEP0 = render_to_string('account_validated.html', context_instance=RequestContext(request))
330 # DEPRECATED # STEP2_HTML = """
331 # DEPRECATED # coucou
333 # DEPRECATED # STEP4 = """
336 # DEPRECATED # STEP5 = render_to_string('account_validated.html', context_instance=RequestContext(request))
338 # DEPRECATED # p = PortalPage(request)
340 # DEPRECATED # # This is redundant with the Wizard title
341 # DEPRECATED # p << "<h3>User registration</h3>"
343 # DEPRECATED # sons = []
344 # DEPRECATED # start_step = 1
346 # DEPRECATED # # STEP 1
347 # DEPRECATED # # If the user already exists (is logged), let's display a summary of his account details
348 # DEPRECATED # # Otherwise propose a form to fill in
349 # DEPRECATED # if the_user(request):
350 # DEPRECATED # # Fill a disabled form with user info
351 # DEPRECATED # # Please logout to register another user
352 # DEPRECATED # sons.append(Raw(page=p, title=STEP1_TITLE, togglable=False, html=STEP0))
353 # DEPRECATED # start_step += 1
355 # DEPRECATED # # We could pass a list of fields also, instead of retrieving them from metadata
356 # DEPRECATED # # Otherwise we need some heuristics to display nice forms
357 # DEPRECATED # # XXX Could we log the user in after the form is validated ?
358 # DEPRECATED # # XXX Explain the password is for XXX
359 # DEPRECATED # field_list = [{
360 # DEPRECATED # 'name' : 'First name',
361 # DEPRECATED # 'field' : 'firstname',
362 # DEPRECATED # 'type' : 'text',
363 # DEPRECATED # 'validate_rx' : '^[a-zA-Z -]+$',
364 # DEPRECATED # 'validate_err': 'Your first name must be comprised of letters only',
365 # DEPRECATED # 'description' : 'Enter your first name',
367 # DEPRECATED # 'name' : 'Last name',
368 # DEPRECATED # 'field' : 'lastname',
369 # DEPRECATED # 'type' : 'text',
370 # DEPRECATED # 'validate_rx' : '^[a-zA-Z -]+$',
371 # DEPRECATED # 'validate_err': 'Your last name must be comprised of letters only',
372 # DEPRECATED # 'description' : 'Enter your last name',
374 # DEPRECATED # 'name' : 'Email',
375 # DEPRECATED # 'field' : 'email',
376 # DEPRECATED # 'type' : 'text',
377 # DEPRECATED # 'description' : 'Enter your email address',
379 # DEPRECATED # 'name' : 'Password',
380 # DEPRECATED # 'field' : 'password',
381 # DEPRECATED # 'type' : 'password',
382 # DEPRECATED # 'description' : 'Enter your password',
384 # DEPRECATED # 'name' : 'Confirm password',
385 # DEPRECATED # 'field' : 'password2',
386 # DEPRECATED # 'type' : 'password',
387 # DEPRECATED # 'description' : 'Enter your password again',
389 # DEPRECATED # sons.append(CreateForm(page = p, title = STEP1_TITLE, togglable = False, object = 'local:user', fields = field_list))
391 # DEPRECATED # # STEP 2
392 # DEPRECATED # # If the user already exists (is logged), let's display a summary of its institution
393 # DEPRECATED # # Otherwise propose a form to fill in (we should base our selection on the email)
394 # DEPRECATED # if the_user(request):
395 # DEPRECATED # # Fill a disabled form with institution
396 # DEPRECATED # # Please logout to register another user
397 # DEPRECATED # sons.append(Raw(page=p, title=STEP2_TITLE, togglable=False, html="User created"))
398 # DEPRECATED # start_step += 1
400 # DEPRECATED # sons.append(CreateForm(page = p, title = STEP2_TITLE, togglable = False, object = 'slice')) #institution'))
402 # DEPRECATED # # STEP3
403 # DEPRECATED # # Please should your prefered authentication method
404 # DEPRECATED # # This step should allow the user to either choose the user or managed mode in MySlice
405 # DEPRECATED # sons.append(Raw(page = p, title = STEP3_TITLE, togglable = False, html = STEP2_HTML))
407 # DEPRECATED # # Step 4: Request a slice (optional)
408 # DEPRECATED # sons.append(CreateForm(page = p, title = STEP4_TITLE, togglable = False, object = 'slice'))
410 # DEPRECATED # # Step 5: Your request is waiting for validation
411 # DEPRECATED # # Periodic refresh
412 # DEPRECATED # sons.append(Raw(page = p, title = STEP5_TITLE, togglable = False, html = STEP4))
414 # DEPRECATED # # Step 6: Account validation = welcome for newly validated users
415 # DEPRECATED # # . delegation
416 # DEPRECATED # # . platforms
417 # DEPRECATED # # . slice
418 # DEPRECATED # # . pointers
419 # DEPRECATED # sons.append(Raw(page = p, title = STEP6_TITLE, togglable = False, html = STEP5))
421 # DEPRECATED # wizard = Wizard(
422 # DEPRECATED # page = p,
423 # DEPRECATED # title = WIZARD_TITLE,
424 # DEPRECATED # togglable = False,
425 # DEPRECATED # sons = sons,
426 # DEPRECATED # start_step = start_step,
429 # DEPRECATED # p << wizard.render(request) # in portal page if possible
431 # DEPRECATED # return p.render()
434 # DEPRECATED ## view for my_account
435 # DEPRECATED # class MyAccountView(TemplateView):
436 # DEPRECATED # template_name = "my_account.html"
438 # DEPRECATED # def from_process(self, request, **cleaned_data):
439 # DEPRECATED # #if request.method == 'POST':
440 # DEPRECATED # # if request.POST['submit_name']:
441 # DEPRECATED # if 'fname' in request.POST:
442 # DEPRECATED # messsag= "Got Name"
443 # DEPRECATED # #return render(request, 'portal/my_account.html')
444 # DEPRECATED # #response = HttpResponse("Here's the text of the Web page.")
445 # DEPRECATED # return HttpResponse(message)
447 # DEPRECATED # def get_context_data(self, **kwargs):
448 # DEPRECATED # page = Page(self.request)
449 # DEPRECATED # context = super(MyAccountView, self).get_context_data(**kwargs)
450 # DEPRECATED # context['person'] = self.request.user
451 # DEPRECATED # # XXX This is repeated in all pages
452 # DEPRECATED # # more general variables expected in the template
453 # DEPRECATED # context['title'] = 'User Profile Page'
454 # DEPRECATED # # the menu items on the top
455 # DEPRECATED # context['topmenu_items'] = topmenu_items('my_account', self.request)
456 # DEPRECATED # # so we can sho who is logged
457 # DEPRECATED # context['username'] = the_user(self.request)
458 # DEPRECATED # context.update(page.prelude_env())
459 # DEPRECATED # return context
463 # View for my_account form
464 def my_account(request):
465 return render(request, 'my_account.html')
467 #my_acc form value processing
468 def acc_process(request):
469 # getting the user_id from the session [now hardcoded]
470 get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
471 if 'submit_name' in request.POST:
472 edited_first_name = request.POST['fname']
473 edited_last_name = request.POST['lname']
474 #email = 'test_email@gmail.com'
475 #password = 'test_pp'
476 #message = 'F_Name: %s L_name: %s dummy_pp: %s' % (first_name, last_name, password)
479 # insert into DB [needed for registration page]
480 #approach borrowed from register view
481 #new_user = PendingUser.objects.create_inactive_user(edited_first_name, edited_last_name, email, password, site)
482 #conventional approach
483 #b = PendingUser(first_name=edited_first_name, edited_last_name=last_name)
486 # select and update [will be used throughout this view]
487 # select the logged in user [for the moment hard coded]
488 #get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
489 # update first and last name
490 get_user.first_name = edited_first_name
491 get_user.last_name = edited_last_name
494 return HttpResponse('Success: Name Updated!!')
495 elif 'submit_pass' in request.POST:
496 edited_password = request.POST['password']
497 # select the logged in user [for the moment hard coded]
498 #get_user = PendingUser.objects.get(id='1') # here we will get the id/email from session e.g., person.email
500 get_user.password = edited_password
502 return HttpResponse('Success: Password Changed!!')
503 elif 'generate' in request.POST:
505 message = 'Here will generate ssh-rsa keys :D %d' %a
506 return HttpResponse(message)
507 elif 'upload_key' in request.POST:
508 up_file = request.FILES['pubkey']
509 file_content = up_file.read()
510 file_name = up_file.name
511 file_extension = os.path.splitext(file_name)[1]
512 allowed_extension = ['.pub','.txt']
513 if file_extension in allowed_extension:
514 file_content = '{user_public_key:'+ file_content +'}'
515 file_content = re.sub("\r", "", file_content)
516 file_content = re.sub("\n", "\\n",file_content)
517 get_user.keypair = file_content
519 return HttpResponse('Success: Publickey uploaded! Old records overwritten')
521 return HttpResponse('Please upload a valid public key.')
524 message = 'You submitted an empty form.'
525 return HttpResponse(message)
529 # view for contact form
530 def contact(request):
531 if request.method == 'POST': # If the form has been submitted...
532 form = ContactForm(request.POST) # A form bound to the POST data
533 if form.is_valid(): # All validation rules pass
534 # Process the data in form.cleaned_data
535 first_name = form.cleaned_data['first_name']
536 last_name = form.cleaned_data['last_name']
537 affiliation = form.cleaned_data['affiliation']
538 subject = form.cleaned_data['subject']
539 message = form.cleaned_data['message']
540 email = form.cleaned_data['email'] # email of the sender
541 cc_myself = form.cleaned_data['cc_myself']
543 recipients = ['yasin.upmc@gmail.com']
545 recipients.append(email)
547 from django.core.mail import send_mail
548 send_mail("Onelab user submitted a query ", [first_name,last_name,affiliation,subject,message], email, recipients)
549 return render(request,'contact_sent.html') # Redirect after POST
551 form = ContactForm() # An unbound form
553 return render(request, 'contact.html', {
558 def slice_request(request):
559 if request.method == 'POST': # If the form has been submitted...
560 form = SliceRequestForm(request.POST) # A form bound to the POST data
561 if form.is_valid(): # All validation rules pass
562 # Process the data in form.cleaned_data
563 slice_name = form.cleaned_data['slice_name']
564 number_of_nodes = form.cleaned_data['number_of_nodes']
565 type_of_nodes = form.cleaned_data['type_of_nodes']
566 purpose = form.cleaned_data['purpose']
567 email = form.cleaned_data['email'] # email of the sender
568 cc_myself = form.cleaned_data['cc_myself']
570 recipients = ['yasin.upmc@gmail.com','jordan.auge@lip6.fr']
572 recipients.append(email)
574 from django.core.mail import send_mail
575 send_mail("Onelab New Slice request form submitted", [slice_name,number_of_nodes,type_of_nodes,purpose], email, recipients)
576 return render(request,'slicereq_recvd.html') # Redirect after POST
578 form = SliceRequestForm() # An unbound form
581 # template_env['form'] = form
582 # template_env['topmenu_items'] = topmenu_items('Request a slice', request)
583 # template_env['unfold1_main'] = render(request, 'slice_request_.html', {
586 # from django.shortcuts import render_to_response
587 # from django.template import RequestContext
588 # return render_to_response ('view-unfold1.html',template_env,
589 # context_instance=RequestContext(request))
591 return render(request, 'slice_request.html', {
593 'topmenu_items': topmenu_items('Request a slice', request),
594 'username': the_user (request)