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