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
40 class DashboardView(TemplateView):
41 template_name = "dashboard.html"
43 def get_context_data(self, **kwargs):
44 user_hrn = 'ple.upmc.jordan_auge'
46 #messages.info(self.request, 'You have logged in')
47 page = Page(self.request)
50 #slice_query = Query().get('slice').filter_by('user.user_hrn', 'contains', user_hrn).select('slice_hrn')
51 slice_query = Query().get('user').filter_by('user_hrn', '==', user_hrn).select('slice.slice_hrn')
52 auth_query = Query().get('network').select('network_hrn')
53 page.enqueue_query(slice_query)
54 page.enqueue_query(auth_query)
58 slicelist = SimpleList(
61 key = 'slice.slice_hrn',
65 authlist = SimpleList(
72 context = super(DashboardView, self).get_context_data(**kwargs)
73 context['person'] = self.request.user
74 context['networks'] = authlist.render(self.request)
75 context['slices'] = slicelist.render(self.request)
77 # XXX This is repeated in all pages
78 # more general variables expected in the template
79 context['title'] = 'Test view that combines various plugins'
80 # the menu items on the top
81 context['topmenu_items'] = topmenu_items('dashboard', self.request)
82 # so we can sho who is logged
83 context['username'] = the_user(self.request)
85 context.update(page.prelude_env())
89 class UserRegisterView(RegistrationView):
91 A registration backend which follows a simple workflow:
93 1. User signs up, inactive account is created.
95 2. Email is sent to user with activation link.
97 3. User clicks activation link, account is now active.
99 Using this backend requires that
101 * ``registration`` be listed in the ``INSTALLED_APPS`` setting
102 (since this backend makes use of models defined in this
105 * The setting ``ACCOUNT_ACTIVATION_DAYS`` be supplied, specifying
106 (as an integer) the number of days from registration during
107 which a user may activate their account (after that period
108 expires, activation will be disallowed).
110 * The creation of the templates
111 ``registration/activation_email_subject.txt`` and
112 ``registration/activation_email.txt``, which will be used for
113 the activation email. See the notes for this backends
114 ``register`` method for details regarding these templates.
116 Additionally, registration can be temporarily closed by adding the
117 setting ``REGISTRATION_OPEN`` and setting it to
118 ``False``. Omitting this setting, or setting it to ``True``, will
119 be interpreted as meaning that registration is currently open and
122 Internally, this is accomplished via storing an activation key in
123 an instance of ``registration.models.RegistrationProfile``. See
124 that model and its custom manager for full documentation of its
125 fields and supported operations.
128 form_class = UserRegisterForm
130 def register(self, request, **cleaned_data):
132 Given a username, email address and password, register a new
133 user account, which will initially be inactive.
135 Along with the new ``User`` object, a new
136 ``registration.models.RegistrationProfile`` will be created,
137 tied to that ``User``, containing the activation key which
138 will be used for this account.
140 An email will be sent to the supplied email address; this
141 email should contain an activation link. The email will be
142 rendered using two templates. See the documentation for
143 ``RegistrationProfile.send_activation_email()`` for
144 information about these templates and the contexts provided to
147 After the ``User`` and ``RegistrationProfile`` are created and
148 the activation email is sent, the signal
149 ``registration.signals.user_registered`` will be sent, with
150 the new ``User`` as the keyword argument ``user`` and the
151 class of this backend as the sender.
154 first_name = cleaned_data['first_name']
155 last_name = cleaned_data['last_name']
156 affiliation= cleaned_data['affiliation']
157 email = cleaned_data['email']
158 password = cleaned_data['password1']
160 #password2 = cleaned_data['password2']
161 keypair = cleaned_data['keypair']
163 #if Site._meta.installed:
164 # site = Site.objects.get_current()
166 # site = RequestSite(request)
169 new_user = PendingUser.objects.create_inactive_user(first_name, last_name, email, password, site)
170 signals.user_registered.send(sender=self.__class__,
175 def registration_allowed(self, request):
177 Indicate whether account registration is currently permitted,
178 based on the value of the setting ``REGISTRATION_OPEN``. This
179 is determined as follows:
181 * If ``REGISTRATION_OPEN`` is not specified in settings, or is
182 set to ``True``, registration is permitted.
184 * If ``REGISTRATION_OPEN`` is both specified and set to
185 ``False``, registration is not permitted.
188 return getattr(settings, 'REGISTRATION_OPEN', True)
190 def get_success_url(self, request, user):
192 Return the name of the URL to redirect to after successful
196 return ('user_register_complete', (), {})
199 class UserValidateView(ActivationView):
200 def activate(self, request, activation_key):
202 Given an an activation key, look up and activate the user
203 account corresponding to that key (if possible).
205 After successful activation, the signal
206 ``registration.signals.user_activated`` will be sent, with the
207 newly activated ``User`` as the keyword argument ``user`` and
208 the class of this backend as the sender.
211 activated_user = RegistrationProfile.objects.activate_user(activation_key)
213 signals.user_activated.send(sender=self.__class__,
216 return activated_user
218 def get_success_url(self, request, user):
219 return ('registration_activation_complete', (), {})
222 # DEPRECATED #from portal.portalpage import PortalPage
223 # DEPRECATED #from plugins.wizard import Wizard
224 # DEPRECATED #from plugins.form import CreateForm
225 # DEPRECATED #from plugins.raw.raw import Raw # XXX
227 # DEPRECATED #from myslice.viewutils import the_user
229 # DEPRECATED #from django.template.loader import render_to_string
230 # DEPRECATED #from django.template import RequestContext
231 # DEPRECATED #from django.views import generic
233 # DEPRECATED #from django.contrib.formtools.wizard.views import NamedUrlSessionWizardView
234 # DEPRECATED ##from django.core.files.storage import FileSystemStorage
235 # DEPRECATED #from django.core.files.storage import default_storage
237 # DEPRECATED ##class MerlinWizard(NamedUrlSessionWizardView):
242 # DEPRECATED ## @classonlymethod
243 # DEPRECATED ## def as_view(cls, *args, **kwargs):
244 # DEPRECATED ## kwargs.update({
245 # DEPRECATED ## 'form_list': [
246 # DEPRECATED ## NameForm,
247 # DEPRECATED ## QuestForm,
248 # DEPRECATED ## ColorForm,
250 # DEPRECATED ## 'url_name': 'merlin_wizard'
252 # DEPRECATED ## return super(MerlinWizard, cls).as_view(*args, **kwargs)
254 # DEPRECATED #class UserRegisterWizardView(NamedUrlSessionWizardView):
255 # DEPRECATED ##class UserRegisterWizardView(LoginRequiredMixin, NamedUrlSessionWizardView):
256 # DEPRECATED # # Notice that I specify a file storage instance. If you don't specify this,
257 # DEPRECATED # # and you need to support FileField or ImageField in your forms, you'll get
258 # DEPRECATED # # errors from Django. This is something else I think could be handled by
259 # DEPRECATED # # the views better. Seems to me that it should just use whatever the
260 # DEPRECATED # # default/specified storage is for the rest of your project/application.
261 # DEPRECATED # file_storage = default_storage # FileSystemStorage()
262 # DEPRECATED # template_name = "register_user_wizard.html"
264 # DEPRECATED # def done(self, form_list, **kwargs):
265 # DEPRECATED # step1_form = form_list[0]
266 # DEPRECATED # step2_form = form_list[1]
268 # DEPRECATED # productext = self.create_product(product_form)
269 # DEPRECATED # shippings = self.create_shippings(productext, shipping_forms)
270 # DEPRECATED # images = self.create_images(productext, image_forms)
272 # DEPRECATED # if all([productext, shippings, images]):
273 # DEPRECATED # del self.request.session["wizard_product_wizard_view"]
275 # DEPRECATED # messages.success(self.request,
276 # DEPRECATED # _("Your product has been created."))
277 # DEPRECATED # return HttpResponseRedirect(self.get_success_url(productext))
279 # DEPRECATED # messages.error(self.request, _("Something went wrong creating your "
280 # DEPRECATED # "product. Please try again or contact support."))
281 # DEPRECATED # return HttpResponseRedirect(reverse("register_wizard"))
283 # DEPRECATED # #def get_form_kwargs(self, step):
284 # DEPRECATED # # if step == "product":
285 # DEPRECATED # # return {"user": self.request.user}
286 # DEPRECATED # # return {}
288 # DEPRECATED ## The portal should hook the slice and user creation pages
290 # DEPRECATED #def register_user(request):
292 # DEPRECATED # if request.method == 'POST':
293 # DEPRECATED # form = UserRegisterForm(request.POST) # Nous reprenons les données
294 # DEPRECATED # if form.is_valid():
295 # DEPRECATED # first_name = form.cleaned_data['first_name']
296 # DEPRECATED # last_name = form.cleaned_data['last_name']
297 # DEPRECATED # email = form.cleaned_data['email']
298 # DEPRECATED # password = form.cleaned_data['password']
299 # DEPRECATED # password2 = form.cleaned_data['password2']
300 # DEPRECATED # keypair = form.cleaned_data['keypair']
301 # DEPRECATED # ## Ici nous pouvons traiter les données du formulaire
302 # DEPRECATED # #sujet = form.cleaned_data['sujet']
303 # DEPRECATED # #message = form.cleaned_data['message']
304 # DEPRECATED # #envoyeur = form.cleaned_data['envoyeur']
305 # DEPRECATED # #renvoi = form.cleaned_data['renvoi']
306 # DEPRECATED # ## Nous pourrions ici envoyer l'e-mail grâce aux données que nous venons de récupérer
307 # DEPRECATED # #envoi = True
309 # DEPRECATED # form = UserRegisterForm()
310 # DEPRECATED # return render(request, 'register_user.html', locals())
312 # DEPRECATED #def index(request):
314 # DEPRECATED # WIZARD_TITLE = 'User registration'
315 # DEPRECATED # STEP1_TITLE = 'Enter your details'
316 # DEPRECATED # STEP2_TITLE = 'Select your institution'
317 # DEPRECATED # STEP3_TITLE = 'Authentication'
318 # DEPRECATED # STEP4_TITLE = 'Request a slice (optional)'
319 # DEPRECATED # STEP5_TITLE = 'Waiting for validation'
320 # DEPRECATED # STEP6_TITLE = 'Account validated'
322 # DEPRECATED # STEP0 = render_to_string('account_validated.html', context_instance=RequestContext(request))
323 # DEPRECATED # STEP2_HTML = """
324 # DEPRECATED # coucou
326 # DEPRECATED # STEP4 = """
329 # DEPRECATED # STEP5 = render_to_string('account_validated.html', context_instance=RequestContext(request))
331 # DEPRECATED # p = PortalPage(request)
333 # DEPRECATED # # This is redundant with the Wizard title
334 # DEPRECATED # p << "<h3>User registration</h3>"
336 # DEPRECATED # sons = []
337 # DEPRECATED # start_step = 1
339 # DEPRECATED # # STEP 1
340 # DEPRECATED # # If the user already exists (is logged), let's display a summary of his account details
341 # DEPRECATED # # Otherwise propose a form to fill in
342 # DEPRECATED # if the_user(request):
343 # DEPRECATED # # Fill a disabled form with user info
344 # DEPRECATED # # Please logout to register another user
345 # DEPRECATED # sons.append(Raw(page=p, title=STEP1_TITLE, togglable=False, html=STEP0))
346 # DEPRECATED # start_step += 1
348 # DEPRECATED # # We could pass a list of fields also, instead of retrieving them from metadata
349 # DEPRECATED # # Otherwise we need some heuristics to display nice forms
350 # DEPRECATED # # XXX Could we log the user in after the form is validated ?
351 # DEPRECATED # # XXX Explain the password is for XXX
352 # DEPRECATED # field_list = [{
353 # DEPRECATED # 'name' : 'First name',
354 # DEPRECATED # 'field' : 'firstname',
355 # DEPRECATED # 'type' : 'text',
356 # DEPRECATED # 'validate_rx' : '^[a-zA-Z -]+$',
357 # DEPRECATED # 'validate_err': 'Your first name must be comprised of letters only',
358 # DEPRECATED # 'description' : 'Enter your first name',
360 # DEPRECATED # 'name' : 'Last name',
361 # DEPRECATED # 'field' : 'lastname',
362 # DEPRECATED # 'type' : 'text',
363 # DEPRECATED # 'validate_rx' : '^[a-zA-Z -]+$',
364 # DEPRECATED # 'validate_err': 'Your last name must be comprised of letters only',
365 # DEPRECATED # 'description' : 'Enter your last name',
367 # DEPRECATED # 'name' : 'Email',
368 # DEPRECATED # 'field' : 'email',
369 # DEPRECATED # 'type' : 'text',
370 # DEPRECATED # 'description' : 'Enter your email address',
372 # DEPRECATED # 'name' : 'Password',
373 # DEPRECATED # 'field' : 'password',
374 # DEPRECATED # 'type' : 'password',
375 # DEPRECATED # 'description' : 'Enter your password',
377 # DEPRECATED # 'name' : 'Confirm password',
378 # DEPRECATED # 'field' : 'password2',
379 # DEPRECATED # 'type' : 'password',
380 # DEPRECATED # 'description' : 'Enter your password again',
382 # DEPRECATED # sons.append(CreateForm(page = p, title = STEP1_TITLE, togglable = False, object = 'local:user', fields = field_list))
384 # DEPRECATED # # STEP 2
385 # DEPRECATED # # If the user already exists (is logged), let's display a summary of its institution
386 # DEPRECATED # # Otherwise propose a form to fill in (we should base our selection on the email)
387 # DEPRECATED # if the_user(request):
388 # DEPRECATED # # Fill a disabled form with institution
389 # DEPRECATED # # Please logout to register another user
390 # DEPRECATED # sons.append(Raw(page=p, title=STEP2_TITLE, togglable=False, html="User created"))
391 # DEPRECATED # start_step += 1
393 # DEPRECATED # sons.append(CreateForm(page = p, title = STEP2_TITLE, togglable = False, object = 'slice')) #institution'))
395 # DEPRECATED # # STEP3
396 # DEPRECATED # # Please should your prefered authentication method
397 # DEPRECATED # # This step should allow the user to either choose the user or managed mode in MySlice
398 # DEPRECATED # sons.append(Raw(page = p, title = STEP3_TITLE, togglable = False, html = STEP2_HTML))
400 # DEPRECATED # # Step 4: Request a slice (optional)
401 # DEPRECATED # sons.append(CreateForm(page = p, title = STEP4_TITLE, togglable = False, object = 'slice'))
403 # DEPRECATED # # Step 5: Your request is waiting for validation
404 # DEPRECATED # # Periodic refresh
405 # DEPRECATED # sons.append(Raw(page = p, title = STEP5_TITLE, togglable = False, html = STEP4))
407 # DEPRECATED # # Step 6: Account validation = welcome for newly validated users
408 # DEPRECATED # # . delegation
409 # DEPRECATED # # . platforms
410 # DEPRECATED # # . slice
411 # DEPRECATED # # . pointers
412 # DEPRECATED # sons.append(Raw(page = p, title = STEP6_TITLE, togglable = False, html = STEP5))
414 # DEPRECATED # wizard = Wizard(
415 # DEPRECATED # page = p,
416 # DEPRECATED # title = WIZARD_TITLE,
417 # DEPRECATED # togglable = False,
418 # DEPRECATED # sons = sons,
419 # DEPRECATED # start_step = start_step,
422 # DEPRECATED # p << wizard.render(request) # in portal page if possible
424 # DEPRECATED # return p.render()
426 class MyAccountView(TemplateView):
427 template_name = "my_account.html"
429 def get_context_data(self, **kwargs):
430 #user_hrn = 'ple.upmc.jordan_auge'
432 #messages.info(self.request, 'You have logged in')
433 page = Page(self.request)
436 #slice_query = Query().get('slice').filter_by('user.user_hrn', 'contains', user_hrn).select('slice_hrn')
437 #slice_query = Query().get('user').filter_by('user_hrn', '==', user_hrn).select('slice.slice_hrn')
438 #auth_query = Query().get('network').select('network_hrn')
439 #page.enqueue_query(slice_query)
440 #page.enqueue_query(auth_query)
442 #page.expose_queries()
444 #slicelist = SimpleList(
447 # key = 'slice.slice_hrn',
448 # query = slice_query,
451 #authlist = SimpleList(
454 # key = 'network_hrn',
455 # query = auth_query,
458 context = super(MyAccountView, self).get_context_data(**kwargs)
459 context['person'] = self.request.user
460 #context['networks'] = authlist.render(self.request)
461 #context['slices'] = slicelist.render(self.request)
463 # XXX This is repeated in all pages
464 # more general variables expected in the template
465 context['title'] = 'User Profile Page'
466 # the menu items on the top
467 context['topmenu_items'] = topmenu_items('my_account', self.request)
468 # so we can sho who is logged
469 context['username'] = the_user(self.request)
471 context.update(page.prelude_env())
481 # view for contact form
482 def contact(request):
483 if request.method == 'POST': # If the form has been submitted...
484 form = ContactForm(request.POST) # A form bound to the POST data
485 if form.is_valid(): # All validation rules pass
486 # Process the data in form.cleaned_data
487 first_name = form.cleaned_data['first_name']
488 last_name = form.cleaned_data['last_name']
489 affiliation = form.cleaned_data['affiliation']
490 subject = form.cleaned_data['subject']
491 message = form.cleaned_data['message']
492 email = form.cleaned_data['email'] # email of the sender
493 cc_myself = form.cleaned_data['cc_myself']
495 recipients = ['yasin.upmc@gmail.com']
497 recipients.append(email)
499 from django.core.mail import send_mail
500 send_mail("Onelab user submitted a query ", [first_name,last_name,affiliation,subject,message], email, recipients)
501 return render(request,'contact_sent.html') # Redirect after POST
503 form = ContactForm() # An unbound form
505 return render(request, 'contact.html', {
510 def slice_request(request):
511 if request.method == 'POST': # If the form has been submitted...
512 form = SliceRequestForm(request.POST) # A form bound to the POST data
513 if form.is_valid(): # All validation rules pass
514 # Process the data in form.cleaned_data
515 slice_name = form.cleaned_data['slice_name']
516 number_of_nodes = form.cleaned_data['number_of_nodes']
517 type_of_nodes = form.cleaned_data['type_of_nodes']
518 purpose = form.cleaned_data['purpose']
519 email = form.cleaned_data['email'] # email of the sender
520 cc_myself = form.cleaned_data['cc_myself']
522 recipients = ['yasin.upmc@gmail.com','jordan.auge@lip6.fr']
524 recipients.append(email)
526 from django.core.mail import send_mail
527 send_mail("Onelab New Slice request form submitted", [slice_name,number_of_nodes,type_of_nodes,purpose], email, recipients)
528 return render(request,'slicereq_recvd.html') # Redirect after POST
530 form = SliceRequestForm() # An unbound form
532 return render(request, 'slice_request.html', {