reworked slice page, added ResourcesSelected plugin
[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.views.generic        import View
26 from django.views.generic.base   import TemplateView
27 from django.shortcuts            import render
28 from plugins.lists.simplelist    import SimpleList
29 from portal                      import signals
30 from portal.forms                import UserRegisterForm, SliceRequestForm
31 from portal.util                 import RegistrationView, ActivationView
32 from portal.models               import PendingUser, PendingSlice
33 from manifold.core.query         import Query
34 from unfold.page                 import Page
35 from myslice.viewutils           import topmenu_items, the_user
36
37 class DashboardView(TemplateView):
38     template_name = "dashboard.html"
39
40     def get_context_data(self, **kwargs):
41         user_hrn = 'ple.upmc.jordan_auge'
42
43         page = Page(self.request)
44
45         # Slow...
46         #slice_query = Query().get('slice').filter_by('user.user_hrn', 'contains', user_hrn).select('slice_hrn')
47         slice_query = Query().get('user').filter_by('user_hrn', '==', user_hrn).select('slice.slice_hrn')
48         auth_query  = Query().get('network').select('network_hrn')
49         page.enqueue_query(slice_query)
50         page.enqueue_query(auth_query)
51
52         page.expose_queries()
53
54         slicelist = SimpleList(
55             title = None,
56             page  = page,
57             key   = 'slice.slice_hrn',
58             query = slice_query,
59         )
60          
61         authlist = SimpleList(
62             title = None,
63             page  = page,
64             key   = 'network_hrn',
65             query = auth_query,
66         )
67
68         context = super(DashboardView, self).get_context_data(**kwargs)
69         context['person']   = self.request.user
70         context['networks'] = authlist.render(self.request) 
71         context['slices']   = slicelist.render(self.request)
72
73         # XXX This is repeated in all pages
74         # more general variables expected in the template
75         context['title'] = 'Test view that combines various plugins'
76         # the menu items on the top
77         context['topmenu_items'] = topmenu_items('dashboard', self.request) 
78         # so we can sho who is logged
79         context['username'] = the_user(self.request) 
80
81         context.update(page.prelude_env())
82
83         return context
84
85 class UserRegisterView(RegistrationView):
86     """
87     A registration backend which follows a simple workflow:
88
89     1. User signs up, inactive account is created.
90
91     2. Email is sent to user with activation link.
92
93     3. User clicks activation link, account is now active.
94
95     Using this backend requires that
96
97     * ``registration`` be listed in the ``INSTALLED_APPS`` setting
98       (since this backend makes use of models defined in this
99       application).
100
101     * The setting ``ACCOUNT_ACTIVATION_DAYS`` be supplied, specifying
102       (as an integer) the number of days from registration during
103       which a user may activate their account (after that period
104       expires, activation will be disallowed).
105
106     * The creation of the templates
107       ``registration/activation_email_subject.txt`` and
108       ``registration/activation_email.txt``, which will be used for
109       the activation email. See the notes for this backends
110       ``register`` method for details regarding these templates.
111
112     Additionally, registration can be temporarily closed by adding the
113     setting ``REGISTRATION_OPEN`` and setting it to
114     ``False``. Omitting this setting, or setting it to ``True``, will
115     be interpreted as meaning that registration is currently open and
116     permitted.
117
118     Internally, this is accomplished via storing an activation key in
119     an instance of ``registration.models.RegistrationProfile``. See
120     that model and its custom manager for full documentation of its
121     fields and supported operations.
122     
123     """
124     form_class = UserRegisterForm
125     
126     def register(self, request, **cleaned_data):
127         """
128         Given a username, email address and password, register a new
129         user account, which will initially be inactive.
130
131         Along with the new ``User`` object, a new
132         ``registration.models.RegistrationProfile`` will be created,
133         tied to that ``User``, containing the activation key which
134         will be used for this account.
135
136         An email will be sent to the supplied email address; this
137         email should contain an activation link. The email will be
138         rendered using two templates. See the documentation for
139         ``RegistrationProfile.send_activation_email()`` for
140         information about these templates and the contexts provided to
141         them.
142
143         After the ``User`` and ``RegistrationProfile`` are created and
144         the activation email is sent, the signal
145         ``registration.signals.user_registered`` will be sent, with
146         the new ``User`` as the keyword argument ``user`` and the
147         class of this backend as the sender.
148
149         """
150         first_name = cleaned_data['first_name']
151         last_name  = cleaned_data['last_name']
152         email      = cleaned_data['email']
153         password   = cleaned_data['password1']
154         #password2  = cleaned_data['password2']
155         keypair    = cleaned_data['keypair']
156
157         #if Site._meta.installed:
158         #    site = Site.objects.get_current()
159         #else:
160         #    site = RequestSite(request) 
161         site = None
162
163         new_user = PendingUser.objects.create_inactive_user(first_name, last_name, email, password, site)
164         signals.user_registered.send(sender=self.__class__,
165                                      user=new_user,
166                                      request=request)
167         return new_user
168
169     def registration_allowed(self, request):
170         """
171         Indicate whether account registration is currently permitted,
172         based on the value of the setting ``REGISTRATION_OPEN``. This
173         is determined as follows:
174
175         * If ``REGISTRATION_OPEN`` is not specified in settings, or is
176           set to ``True``, registration is permitted.
177
178         * If ``REGISTRATION_OPEN`` is both specified and set to
179           ``False``, registration is not permitted.
180         
181         """
182         return getattr(settings, 'REGISTRATION_OPEN', True)
183
184     def get_success_url(self, request, user):
185         """
186         Return the name of the URL to redirect to after successful
187         user registration.
188         
189         """
190         return ('user_register_complete', (), {})
191
192
193 class UserValidateView(ActivationView):
194     def activate(self, request, activation_key):
195         """
196         Given an an activation key, look up and activate the user
197         account corresponding to that key (if possible).
198
199         After successful activation, the signal
200         ``registration.signals.user_activated`` will be sent, with the
201         newly activated ``User`` as the keyword argument ``user`` and
202         the class of this backend as the sender.
203         
204         """
205         activated_user = RegistrationProfile.objects.activate_user(activation_key)
206         if activated_user:
207             signals.user_activated.send(sender=self.__class__,
208                                         user=activated_user,
209                                         request=request)
210         return activated_user
211
212     def get_success_url(self, request, user):
213         return ('registration_activation_complete', (), {})
214
215
216 # DEPRECATED #from portal.portalpage  import PortalPage
217 # DEPRECATED #from plugins.wizard     import Wizard
218 # DEPRECATED #from plugins.form       import CreateForm
219 # DEPRECATED #from plugins.raw.raw    import Raw          # XXX
220 # DEPRECATED #
221 # DEPRECATED #from myslice.viewutils  import the_user
222 # DEPRECATED #
223 # DEPRECATED #from django.template.loader import render_to_string
224 # DEPRECATED #from django.template import RequestContext
225 # DEPRECATED #from django.views import generic
226 # DEPRECATED #
227 # DEPRECATED #from django.contrib.formtools.wizard.views import NamedUrlSessionWizardView
228 # DEPRECATED ##from django.core.files.storage import FileSystemStorage
229 # DEPRECATED #from django.core.files.storage import default_storage
230 # DEPRECATED #
231 # DEPRECATED ##class MerlinWizard(NamedUrlSessionWizardView):
232 # DEPRECATED ##
233 # DEPRECATED ##    ...
234 # DEPRECATED ##    ...
235 # DEPRECATED ##
236 # DEPRECATED ##    @classonlymethod
237 # DEPRECATED ##    def as_view(cls, *args, **kwargs):
238 # DEPRECATED ##        kwargs.update({
239 # DEPRECATED ##            'form_list': [
240 # DEPRECATED ##                NameForm,
241 # DEPRECATED ##                QuestForm,
242 # DEPRECATED ##                ColorForm,
243 # DEPRECATED ##            ],
244 # DEPRECATED ##            'url_name': 'merlin_wizard'
245 # DEPRECATED ##        })
246 # DEPRECATED ##        return super(MerlinWizard, cls).as_view(*args, **kwargs)
247 # DEPRECATED #
248 # DEPRECATED #class UserRegisterWizardView(NamedUrlSessionWizardView):
249 # DEPRECATED ##class UserRegisterWizardView(LoginRequiredMixin, NamedUrlSessionWizardView):
250 # DEPRECATED #    # Notice that I specify a file storage instance. If you don't specify this,
251 # DEPRECATED #    # and you need to support FileField or ImageField in your forms, you'll get
252 # DEPRECATED #    # errors from Django. This is something else I think could be handled by
253 # DEPRECATED #    # the views better. Seems to me that it should just use whatever the
254 # DEPRECATED #    # default/specified storage is for the rest of your project/application.
255 # DEPRECATED #    file_storage = default_storage # FileSystemStorage()
256 # DEPRECATED #    template_name = "register_user_wizard.html"
257 # DEPRECATED #
258 # DEPRECATED #    def done(self, form_list, **kwargs):
259 # DEPRECATED #        step1_form = form_list[0]
260 # DEPRECATED #        step2_form = form_list[1]
261 # DEPRECATED #
262 # DEPRECATED #        productext = self.create_product(product_form)
263 # DEPRECATED #        shippings = self.create_shippings(productext, shipping_forms)
264 # DEPRECATED #        images = self.create_images(productext, image_forms)
265 # DEPRECATED #
266 # DEPRECATED #        if all([productext, shippings, images]):
267 # DEPRECATED #            del self.request.session["wizard_product_wizard_view"]
268 # DEPRECATED #
269 # DEPRECATED #            messages.success(self.request,
270 # DEPRECATED #                _("Your product has been created."))
271 # DEPRECATED #            return HttpResponseRedirect(self.get_success_url(productext))
272 # DEPRECATED #
273 # DEPRECATED #        messages.error(self.request, _("Something went wrong creating your "
274 # DEPRECATED #            "product. Please try again or contact support."))
275 # DEPRECATED #        return HttpResponseRedirect(reverse("register_wizard"))
276 # DEPRECATED #
277 # DEPRECATED #    #def get_form_kwargs(self, step):
278 # DEPRECATED #    #    if step == "product":
279 # DEPRECATED #    #        return {"user": self.request.user}
280 # DEPRECATED #    #    return {}
281 # DEPRECATED #
282 # DEPRECATED ## The portal should hook the slice and user creation pages
283 # DEPRECATED #
284 # DEPRECATED #def register_user(request):
285 # DEPRECATED #    
286 # DEPRECATED #    if request.method == 'POST':
287 # DEPRECATED #        form = UserRegisterForm(request.POST) # Nous reprenons les données
288 # DEPRECATED #        if form.is_valid():
289 # DEPRECATED #            first_name = form.cleaned_data['first_name']
290 # DEPRECATED #            last_name  = form.cleaned_data['last_name']
291 # DEPRECATED #            email      = form.cleaned_data['email']
292 # DEPRECATED #            password   = form.cleaned_data['password']
293 # DEPRECATED #            password2  = form.cleaned_data['password2']
294 # DEPRECATED #            keypair    = form.cleaned_data['keypair']
295 # DEPRECATED #            ## Ici nous pouvons traiter les données du formulaire
296 # DEPRECATED #            #sujet = form.cleaned_data['sujet']
297 # DEPRECATED #            #message = form.cleaned_data['message']
298 # DEPRECATED #            #envoyeur = form.cleaned_data['envoyeur']
299 # DEPRECATED #            #renvoi = form.cleaned_data['renvoi']
300 # DEPRECATED #            ## Nous pourrions ici envoyer l'e-mail grâce aux données que nous venons de récupérer
301 # DEPRECATED #            #envoi = True
302 # DEPRECATED #    else:
303 # DEPRECATED #        form = UserRegisterForm()
304 # DEPRECATED #    return render(request, 'register_user.html', locals())
305 # DEPRECATED #
306 # DEPRECATED #def index(request):
307 # DEPRECATED #
308 # DEPRECATED #    WIZARD_TITLE = 'User registration'
309 # DEPRECATED #    STEP1_TITLE  = 'Enter your details'
310 # DEPRECATED #    STEP2_TITLE  = 'Select your institution'
311 # DEPRECATED #    STEP3_TITLE  = 'Authentication'
312 # DEPRECATED #    STEP4_TITLE  = 'Request a slice (optional)'
313 # DEPRECATED #    STEP5_TITLE  = 'Waiting for validation'
314 # DEPRECATED #    STEP6_TITLE  = 'Account validated'
315 # DEPRECATED #
316 # DEPRECATED #    STEP0 = render_to_string('account_validated.html', context_instance=RequestContext(request))
317 # DEPRECATED #    STEP2_HTML   = """
318 # DEPRECATED #    coucou
319 # DEPRECATED #    """
320 # DEPRECATED #    STEP4 = """
321 # DEPRECATED #    mede
322 # DEPRECATED #    """
323 # DEPRECATED #    STEP5 = render_to_string('account_validated.html', context_instance=RequestContext(request))
324 # DEPRECATED #
325 # DEPRECATED #    p = PortalPage(request)
326 # DEPRECATED #
327 # DEPRECATED #    # This is redundant with the Wizard title
328 # DEPRECATED #    p << "<h3>User registration</h3>"
329 # DEPRECATED #
330 # DEPRECATED #    sons = []
331 # DEPRECATED #    start_step = 1
332 # DEPRECATED #
333 # DEPRECATED #    # STEP 1
334 # DEPRECATED #    # If the user already exists (is logged), let's display a summary of his account details
335 # DEPRECATED #    # Otherwise propose a form to fill in
336 # DEPRECATED #    if the_user(request):
337 # DEPRECATED #        # Fill a disabled form with user info
338 # DEPRECATED #        # Please logout to register another user
339 # DEPRECATED #        sons.append(Raw(page=p, title=STEP1_TITLE, togglable=False, html=STEP0))
340 # DEPRECATED #        start_step += 1
341 # DEPRECATED #    else:
342 # DEPRECATED #        # We could pass a list of fields also, instead of retrieving them from metadata
343 # DEPRECATED #        # Otherwise we need some heuristics to display nice forms
344 # DEPRECATED #        # XXX Could we log the user in after the form is validated ?
345 # DEPRECATED #        # XXX Explain the password is for XXX
346 # DEPRECATED #        field_list = [{
347 # DEPRECATED #            'name'        : 'First name',
348 # DEPRECATED #            'field'       : 'firstname',
349 # DEPRECATED #            'type'        : 'text',
350 # DEPRECATED #            'validate_rx' : '^[a-zA-Z -]+$',
351 # DEPRECATED #            'validate_err': 'Your first name must be comprised of letters only',
352 # DEPRECATED #            'description' : 'Enter your first name',
353 # DEPRECATED #        }, {
354 # DEPRECATED #            'name'        : 'Last name',
355 # DEPRECATED #            'field'       : 'lastname',
356 # DEPRECATED #            'type'        : 'text',
357 # DEPRECATED #            'validate_rx' : '^[a-zA-Z -]+$',
358 # DEPRECATED #            'validate_err': 'Your last name must be comprised of letters only',
359 # DEPRECATED #            'description' : 'Enter your last name',
360 # DEPRECATED #        }, { 
361 # DEPRECATED #            'name'        : 'Email',
362 # DEPRECATED #            'field'       : 'email',
363 # DEPRECATED #            'type'        : 'text',
364 # DEPRECATED #            'description' : 'Enter your email address',
365 # DEPRECATED #        }, {
366 # DEPRECATED #            'name'        : 'Password',
367 # DEPRECATED #            'field'       : 'password',
368 # DEPRECATED #            'type'        : 'password',
369 # DEPRECATED #            'description' : 'Enter your password',
370 # DEPRECATED #        }, {
371 # DEPRECATED #            'name'        : 'Confirm password',
372 # DEPRECATED #            'field'       : 'password2',
373 # DEPRECATED #            'type'        : 'password',
374 # DEPRECATED #            'description' : 'Enter your password again',
375 # DEPRECATED #        }]
376 # DEPRECATED #        sons.append(CreateForm(page = p, title = STEP1_TITLE, togglable = False, object = 'local:user', fields = field_list))
377 # DEPRECATED #
378 # DEPRECATED #    # STEP 2
379 # DEPRECATED #    # If the user already exists (is logged), let's display a summary of its institution
380 # DEPRECATED #    # Otherwise propose a form to fill in (we should base our selection on the email)
381 # DEPRECATED #    if the_user(request):
382 # DEPRECATED #        # Fill a disabled form with institution
383 # DEPRECATED #        # Please logout to register another user
384 # DEPRECATED #        sons.append(Raw(page=p, title=STEP2_TITLE, togglable=False, html="User created"))
385 # DEPRECATED #        start_step += 1
386 # DEPRECATED #    else:
387 # DEPRECATED #        sons.append(CreateForm(page = p, title = STEP2_TITLE, togglable = False, object = 'slice')) #institution'))
388 # DEPRECATED #
389 # DEPRECATED #    # STEP3
390 # DEPRECATED #    # Please should your prefered authentication method
391 # DEPRECATED #    # This step should allow the user to either choose the user or managed mode in MySlice
392 # DEPRECATED #    sons.append(Raw(page = p, title = STEP3_TITLE, togglable = False, html = STEP2_HTML))
393 # DEPRECATED #
394 # DEPRECATED #    # Step 4: Request a slice (optional)
395 # DEPRECATED #    sons.append(CreateForm(page = p, title = STEP4_TITLE, togglable = False, object = 'slice'))
396 # DEPRECATED #
397 # DEPRECATED #    # Step 5: Your request is waiting for validation
398 # DEPRECATED #    # Periodic refresh
399 # DEPRECATED #    sons.append(Raw(page = p, title = STEP5_TITLE, togglable = False, html = STEP4))
400 # DEPRECATED #
401 # DEPRECATED #    # Step 6: Account validation  = welcome for newly validated users
402 # DEPRECATED #    # . delegation
403 # DEPRECATED #    # . platforms
404 # DEPRECATED #    # . slice
405 # DEPRECATED #    # . pointers
406 # DEPRECATED #    sons.append(Raw(page = p, title = STEP6_TITLE, togglable = False, html = STEP5))
407 # DEPRECATED #
408 # DEPRECATED #    wizard = Wizard(
409 # DEPRECATED #        page       = p,
410 # DEPRECATED #        title      = WIZARD_TITLE,
411 # DEPRECATED #        togglable  = False,
412 # DEPRECATED #        sons       = sons,
413 # DEPRECATED #        start_step = start_step,
414 # DEPRECATED #    )
415 # DEPRECATED #
416 # DEPRECATED #    p << wizard.render(request) # in portal page if possible
417 # DEPRECATED #
418 # DEPRECATED #    return p.render()