added sticky notifications for warnings and errors + clean up code for v2 only
[myslice.git] / portal / views.py
1 # -*- coding: utf-8 -*-
2 #
3 # portal/views.py: views for the portal application
4 # This file is part of the Manifold project.
5 #
6 # Authors:
7 #   Jordan Augé <jordan.auge@lip6.fr>
8 # Copyright 2013, UPMC Sorbonne Universités / LIP6
9 #
10 # This program is free software; you can redistribute it and/or modify it under
11 # the terms of the GNU General Public License as published by the Free Software
12 # Foundation; either version 3, or (at your option) any later version.
13
14 # This program is distributed in the hope that it will be useful, but WITHOUT
15 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
17 # details.
18
19 # You should have received a copy of the GNU General Public License along with
20 # this program; see the file COPYING.  If not, write to the Free Software
21 # Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23 from django.conf                 import settings
24 from django.contrib.sites.models import Site, RequestSite
25 from django.contrib              import messages
26 from django.views.generic        import View
27 from django.views.generic.base   import TemplateView
28 from django.shortcuts            import render
29 from plugins.lists.simplelist    import SimpleList
30 from portal                      import signals
31 from portal.forms                import UserRegisterForm, SliceRequestForm
32 from portal.util                 import RegistrationView, ActivationView
33 from portal.models               import PendingUser, PendingSlice
34 from manifold.core.query         import Query
35 from unfold.page                 import Page
36 from myslice.viewutils           import topmenu_items, the_user
37
38 class DashboardView(TemplateView):
39     template_name = "dashboard.html"
40
41     def get_context_data(self, **kwargs):
42         user_hrn = 'ple.upmc.jordan_auge'
43
44         messages.info(self.request, 'You have logged in')
45
46
47         page = Page(self.request)
48
49         # Slow...
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)
55
56         page.expose_queries()
57
58         slicelist = SimpleList(
59             title = None,
60             page  = page,
61             key   = 'slice.slice_hrn',
62             query = slice_query,
63         )
64          
65         authlist = SimpleList(
66             title = None,
67             page  = page,
68             key   = 'network_hrn',
69             query = auth_query,
70         )
71
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)
76
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) 
84
85         context.update(page.prelude_env())
86
87         return context
88
89 class UserRegisterView(RegistrationView):
90     """
91     A registration backend which follows a simple workflow:
92
93     1. User signs up, inactive account is created.
94
95     2. Email is sent to user with activation link.
96
97     3. User clicks activation link, account is now active.
98
99     Using this backend requires that
100
101     * ``registration`` be listed in the ``INSTALLED_APPS`` setting
102       (since this backend makes use of models defined in this
103       application).
104
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).
109
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.
115
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
120     permitted.
121
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.
126     
127     """
128     form_class = UserRegisterForm
129     
130     def register(self, request, **cleaned_data):
131         """
132         Given a username, email address and password, register a new
133         user account, which will initially be inactive.
134
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.
139
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
145         them.
146
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.
152
153         """
154         first_name = cleaned_data['first_name']
155         last_name  = cleaned_data['last_name']
156         email      = cleaned_data['email']
157         password   = cleaned_data['password1']
158         #password2  = cleaned_data['password2']
159         keypair    = cleaned_data['keypair']
160
161         #if Site._meta.installed:
162         #    site = Site.objects.get_current()
163         #else:
164         #    site = RequestSite(request) 
165         site = None
166
167         new_user = PendingUser.objects.create_inactive_user(first_name, last_name, email, password, site)
168         signals.user_registered.send(sender=self.__class__,
169                                      user=new_user,
170                                      request=request)
171         return new_user
172
173     def registration_allowed(self, request):
174         """
175         Indicate whether account registration is currently permitted,
176         based on the value of the setting ``REGISTRATION_OPEN``. This
177         is determined as follows:
178
179         * If ``REGISTRATION_OPEN`` is not specified in settings, or is
180           set to ``True``, registration is permitted.
181
182         * If ``REGISTRATION_OPEN`` is both specified and set to
183           ``False``, registration is not permitted.
184         
185         """
186         return getattr(settings, 'REGISTRATION_OPEN', True)
187
188     def get_success_url(self, request, user):
189         """
190         Return the name of the URL to redirect to after successful
191         user registration.
192         
193         """
194         return ('user_register_complete', (), {})
195
196
197 class UserValidateView(ActivationView):
198     def activate(self, request, activation_key):
199         """
200         Given an an activation key, look up and activate the user
201         account corresponding to that key (if possible).
202
203         After successful activation, the signal
204         ``registration.signals.user_activated`` will be sent, with the
205         newly activated ``User`` as the keyword argument ``user`` and
206         the class of this backend as the sender.
207         
208         """
209         activated_user = RegistrationProfile.objects.activate_user(activation_key)
210         if activated_user:
211             signals.user_activated.send(sender=self.__class__,
212                                         user=activated_user,
213                                         request=request)
214         return activated_user
215
216     def get_success_url(self, request, user):
217         return ('registration_activation_complete', (), {})
218
219
220 # DEPRECATED #from portal.portalpage  import PortalPage
221 # DEPRECATED #from plugins.wizard     import Wizard
222 # DEPRECATED #from plugins.form       import CreateForm
223 # DEPRECATED #from plugins.raw.raw    import Raw          # XXX
224 # DEPRECATED #
225 # DEPRECATED #from myslice.viewutils  import the_user
226 # DEPRECATED #
227 # DEPRECATED #from django.template.loader import render_to_string
228 # DEPRECATED #from django.template import RequestContext
229 # DEPRECATED #from django.views import generic
230 # DEPRECATED #
231 # DEPRECATED #from django.contrib.formtools.wizard.views import NamedUrlSessionWizardView
232 # DEPRECATED ##from django.core.files.storage import FileSystemStorage
233 # DEPRECATED #from django.core.files.storage import default_storage
234 # DEPRECATED #
235 # DEPRECATED ##class MerlinWizard(NamedUrlSessionWizardView):
236 # DEPRECATED ##
237 # DEPRECATED ##    ...
238 # DEPRECATED ##    ...
239 # DEPRECATED ##
240 # DEPRECATED ##    @classonlymethod
241 # DEPRECATED ##    def as_view(cls, *args, **kwargs):
242 # DEPRECATED ##        kwargs.update({
243 # DEPRECATED ##            'form_list': [
244 # DEPRECATED ##                NameForm,
245 # DEPRECATED ##                QuestForm,
246 # DEPRECATED ##                ColorForm,
247 # DEPRECATED ##            ],
248 # DEPRECATED ##            'url_name': 'merlin_wizard'
249 # DEPRECATED ##        })
250 # DEPRECATED ##        return super(MerlinWizard, cls).as_view(*args, **kwargs)
251 # DEPRECATED #
252 # DEPRECATED #class UserRegisterWizardView(NamedUrlSessionWizardView):
253 # DEPRECATED ##class UserRegisterWizardView(LoginRequiredMixin, NamedUrlSessionWizardView):
254 # DEPRECATED #    # Notice that I specify a file storage instance. If you don't specify this,
255 # DEPRECATED #    # and you need to support FileField or ImageField in your forms, you'll get
256 # DEPRECATED #    # errors from Django. This is something else I think could be handled by
257 # DEPRECATED #    # the views better. Seems to me that it should just use whatever the
258 # DEPRECATED #    # default/specified storage is for the rest of your project/application.
259 # DEPRECATED #    file_storage = default_storage # FileSystemStorage()
260 # DEPRECATED #    template_name = "register_user_wizard.html"
261 # DEPRECATED #
262 # DEPRECATED #    def done(self, form_list, **kwargs):
263 # DEPRECATED #        step1_form = form_list[0]
264 # DEPRECATED #        step2_form = form_list[1]
265 # DEPRECATED #
266 # DEPRECATED #        productext = self.create_product(product_form)
267 # DEPRECATED #        shippings = self.create_shippings(productext, shipping_forms)
268 # DEPRECATED #        images = self.create_images(productext, image_forms)
269 # DEPRECATED #
270 # DEPRECATED #        if all([productext, shippings, images]):
271 # DEPRECATED #            del self.request.session["wizard_product_wizard_view"]
272 # DEPRECATED #
273 # DEPRECATED #            messages.success(self.request,
274 # DEPRECATED #                _("Your product has been created."))
275 # DEPRECATED #            return HttpResponseRedirect(self.get_success_url(productext))
276 # DEPRECATED #
277 # DEPRECATED #        messages.error(self.request, _("Something went wrong creating your "
278 # DEPRECATED #            "product. Please try again or contact support."))
279 # DEPRECATED #        return HttpResponseRedirect(reverse("register_wizard"))
280 # DEPRECATED #
281 # DEPRECATED #    #def get_form_kwargs(self, step):
282 # DEPRECATED #    #    if step == "product":
283 # DEPRECATED #    #        return {"user": self.request.user}
284 # DEPRECATED #    #    return {}
285 # DEPRECATED #
286 # DEPRECATED ## The portal should hook the slice and user creation pages
287 # DEPRECATED #
288 # DEPRECATED #def register_user(request):
289 # DEPRECATED #    
290 # DEPRECATED #    if request.method == 'POST':
291 # DEPRECATED #        form = UserRegisterForm(request.POST) # Nous reprenons les données
292 # DEPRECATED #        if form.is_valid():
293 # DEPRECATED #            first_name = form.cleaned_data['first_name']
294 # DEPRECATED #            last_name  = form.cleaned_data['last_name']
295 # DEPRECATED #            email      = form.cleaned_data['email']
296 # DEPRECATED #            password   = form.cleaned_data['password']
297 # DEPRECATED #            password2  = form.cleaned_data['password2']
298 # DEPRECATED #            keypair    = form.cleaned_data['keypair']
299 # DEPRECATED #            ## Ici nous pouvons traiter les données du formulaire
300 # DEPRECATED #            #sujet = form.cleaned_data['sujet']
301 # DEPRECATED #            #message = form.cleaned_data['message']
302 # DEPRECATED #            #envoyeur = form.cleaned_data['envoyeur']
303 # DEPRECATED #            #renvoi = form.cleaned_data['renvoi']
304 # DEPRECATED #            ## Nous pourrions ici envoyer l'e-mail grâce aux données que nous venons de récupérer
305 # DEPRECATED #            #envoi = True
306 # DEPRECATED #    else:
307 # DEPRECATED #        form = UserRegisterForm()
308 # DEPRECATED #    return render(request, 'register_user.html', locals())
309 # DEPRECATED #
310 # DEPRECATED #def index(request):
311 # DEPRECATED #
312 # DEPRECATED #    WIZARD_TITLE = 'User registration'
313 # DEPRECATED #    STEP1_TITLE  = 'Enter your details'
314 # DEPRECATED #    STEP2_TITLE  = 'Select your institution'
315 # DEPRECATED #    STEP3_TITLE  = 'Authentication'
316 # DEPRECATED #    STEP4_TITLE  = 'Request a slice (optional)'
317 # DEPRECATED #    STEP5_TITLE  = 'Waiting for validation'
318 # DEPRECATED #    STEP6_TITLE  = 'Account validated'
319 # DEPRECATED #
320 # DEPRECATED #    STEP0 = render_to_string('account_validated.html', context_instance=RequestContext(request))
321 # DEPRECATED #    STEP2_HTML   = """
322 # DEPRECATED #    coucou
323 # DEPRECATED #    """
324 # DEPRECATED #    STEP4 = """
325 # DEPRECATED #    mede
326 # DEPRECATED #    """
327 # DEPRECATED #    STEP5 = render_to_string('account_validated.html', context_instance=RequestContext(request))
328 # DEPRECATED #
329 # DEPRECATED #    p = PortalPage(request)
330 # DEPRECATED #
331 # DEPRECATED #    # This is redundant with the Wizard title
332 # DEPRECATED #    p << "<h3>User registration</h3>"
333 # DEPRECATED #
334 # DEPRECATED #    sons = []
335 # DEPRECATED #    start_step = 1
336 # DEPRECATED #
337 # DEPRECATED #    # STEP 1
338 # DEPRECATED #    # If the user already exists (is logged), let's display a summary of his account details
339 # DEPRECATED #    # Otherwise propose a form to fill in
340 # DEPRECATED #    if the_user(request):
341 # DEPRECATED #        # Fill a disabled form with user info
342 # DEPRECATED #        # Please logout to register another user
343 # DEPRECATED #        sons.append(Raw(page=p, title=STEP1_TITLE, togglable=False, html=STEP0))
344 # DEPRECATED #        start_step += 1
345 # DEPRECATED #    else:
346 # DEPRECATED #        # We could pass a list of fields also, instead of retrieving them from metadata
347 # DEPRECATED #        # Otherwise we need some heuristics to display nice forms
348 # DEPRECATED #        # XXX Could we log the user in after the form is validated ?
349 # DEPRECATED #        # XXX Explain the password is for XXX
350 # DEPRECATED #        field_list = [{
351 # DEPRECATED #            'name'        : 'First name',
352 # DEPRECATED #            'field'       : 'firstname',
353 # DEPRECATED #            'type'        : 'text',
354 # DEPRECATED #            'validate_rx' : '^[a-zA-Z -]+$',
355 # DEPRECATED #            'validate_err': 'Your first name must be comprised of letters only',
356 # DEPRECATED #            'description' : 'Enter your first name',
357 # DEPRECATED #        }, {
358 # DEPRECATED #            'name'        : 'Last name',
359 # DEPRECATED #            'field'       : 'lastname',
360 # DEPRECATED #            'type'        : 'text',
361 # DEPRECATED #            'validate_rx' : '^[a-zA-Z -]+$',
362 # DEPRECATED #            'validate_err': 'Your last name must be comprised of letters only',
363 # DEPRECATED #            'description' : 'Enter your last name',
364 # DEPRECATED #        }, { 
365 # DEPRECATED #            'name'        : 'Email',
366 # DEPRECATED #            'field'       : 'email',
367 # DEPRECATED #            'type'        : 'text',
368 # DEPRECATED #            'description' : 'Enter your email address',
369 # DEPRECATED #        }, {
370 # DEPRECATED #            'name'        : 'Password',
371 # DEPRECATED #            'field'       : 'password',
372 # DEPRECATED #            'type'        : 'password',
373 # DEPRECATED #            'description' : 'Enter your password',
374 # DEPRECATED #        }, {
375 # DEPRECATED #            'name'        : 'Confirm password',
376 # DEPRECATED #            'field'       : 'password2',
377 # DEPRECATED #            'type'        : 'password',
378 # DEPRECATED #            'description' : 'Enter your password again',
379 # DEPRECATED #        }]
380 # DEPRECATED #        sons.append(CreateForm(page = p, title = STEP1_TITLE, togglable = False, object = 'local:user', fields = field_list))
381 # DEPRECATED #
382 # DEPRECATED #    # STEP 2
383 # DEPRECATED #    # If the user already exists (is logged), let's display a summary of its institution
384 # DEPRECATED #    # Otherwise propose a form to fill in (we should base our selection on the email)
385 # DEPRECATED #    if the_user(request):
386 # DEPRECATED #        # Fill a disabled form with institution
387 # DEPRECATED #        # Please logout to register another user
388 # DEPRECATED #        sons.append(Raw(page=p, title=STEP2_TITLE, togglable=False, html="User created"))
389 # DEPRECATED #        start_step += 1
390 # DEPRECATED #    else:
391 # DEPRECATED #        sons.append(CreateForm(page = p, title = STEP2_TITLE, togglable = False, object = 'slice')) #institution'))
392 # DEPRECATED #
393 # DEPRECATED #    # STEP3
394 # DEPRECATED #    # Please should your prefered authentication method
395 # DEPRECATED #    # This step should allow the user to either choose the user or managed mode in MySlice
396 # DEPRECATED #    sons.append(Raw(page = p, title = STEP3_TITLE, togglable = False, html = STEP2_HTML))
397 # DEPRECATED #
398 # DEPRECATED #    # Step 4: Request a slice (optional)
399 # DEPRECATED #    sons.append(CreateForm(page = p, title = STEP4_TITLE, togglable = False, object = 'slice'))
400 # DEPRECATED #
401 # DEPRECATED #    # Step 5: Your request is waiting for validation
402 # DEPRECATED #    # Periodic refresh
403 # DEPRECATED #    sons.append(Raw(page = p, title = STEP5_TITLE, togglable = False, html = STEP4))
404 # DEPRECATED #
405 # DEPRECATED #    # Step 6: Account validation  = welcome for newly validated users
406 # DEPRECATED #    # . delegation
407 # DEPRECATED #    # . platforms
408 # DEPRECATED #    # . slice
409 # DEPRECATED #    # . pointers
410 # DEPRECATED #    sons.append(Raw(page = p, title = STEP6_TITLE, togglable = False, html = STEP5))
411 # DEPRECATED #
412 # DEPRECATED #    wizard = Wizard(
413 # DEPRECATED #        page       = p,
414 # DEPRECATED #        title      = WIZARD_TITLE,
415 # DEPRECATED #        togglable  = False,
416 # DEPRECATED #        sons       = sons,
417 # DEPRECATED #        start_step = start_step,
418 # DEPRECATED #    )
419 # DEPRECATED #
420 # DEPRECATED #    p << wizard.render(request) # in portal page if possible
421 # DEPRECATED #
422 # DEPRECATED #    return p.render()