1
|
|
|
# -*- coding: utf-8 -*- |
2
|
|
|
from __future__ import unicode_literals |
3
|
|
|
""" |
4
|
|
|
Default registration backend class |
5
|
|
|
|
6
|
|
|
This is a modification of django-registration_ ``admin.py`` |
7
|
|
|
The original code is written by James Bennett |
8
|
|
|
|
9
|
|
|
.. _django-registration: https://bitbucket.org/ubernostrum/django-registration |
10
|
|
|
|
11
|
|
|
Original License:: |
12
|
|
|
|
13
|
|
|
Copyright (c) 2007-2011, James Bennett |
14
|
|
|
All rights reserved. |
15
|
|
|
|
16
|
|
|
Redistribution and use in source and binary forms, with or without |
17
|
|
|
modification, are permitted provided that the following conditions are |
18
|
|
|
met: |
19
|
|
|
|
20
|
|
|
* Redistributions of source code must retain the above copyright |
21
|
|
|
notice, this list of conditions and the following disclaimer. |
22
|
|
|
* Redistributions in binary form must reproduce the above |
23
|
|
|
copyright notice, this list of conditions and the following |
24
|
|
|
disclaimer in the documentation and/or other materials provided |
25
|
|
|
with the distribution. |
26
|
|
|
* Neither the name of the author nor the names of other |
27
|
|
|
contributors may be used to endorse or promote products derived |
28
|
|
|
from this software without specific prior written permission. |
29
|
|
|
|
30
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
31
|
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
32
|
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
33
|
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
34
|
|
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
35
|
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
36
|
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
37
|
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
38
|
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
39
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
40
|
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
41
|
|
|
|
42
|
|
|
""" |
43
|
|
|
__author__ = 'Alisue <[email protected]>' |
44
|
|
|
import sys |
45
|
|
|
from django.core.urlresolvers import reverse |
46
|
|
|
|
47
|
|
|
from registration import signals |
48
|
|
|
from registration.conf import settings |
49
|
|
|
from registration.backends.base import RegistrationBackendBase |
50
|
|
|
from registration.models import RegistrationProfile |
51
|
|
|
from registration.forms import ActivationForm |
52
|
|
|
from registration.forms import RegistrationForm |
53
|
|
|
from registration.supplements import get_supplement_class |
54
|
|
|
|
55
|
|
|
|
56
|
|
|
class DefaultRegistrationBackend(RegistrationBackendBase): |
57
|
|
|
|
58
|
|
|
"""Default registration backend class |
59
|
|
|
|
60
|
|
|
A registration backend which floows a simple workflow: |
61
|
|
|
|
62
|
|
|
1. User sigs up, inactive account with unusable password is created. |
63
|
|
|
|
64
|
|
|
2. Inspector accept or reject the account registration. |
65
|
|
|
|
66
|
|
|
3. Email is sent to user with/without activation link (without when |
67
|
|
|
rejected) |
68
|
|
|
|
69
|
|
|
4. User clicks activation link, enter password, account is now active |
70
|
|
|
|
71
|
|
|
Using this backend requires that |
72
|
|
|
|
73
|
|
|
* ``registration`` be listed in the ``INSTALLED_APPS`` settings |
74
|
|
|
(since this backend makes use of models defined in this application). |
75
|
|
|
|
76
|
|
|
* ``django.contrib.admin`` be listed in the ``INSTALLED_APPS`` settings |
77
|
|
|
|
78
|
|
|
* The setting ``ACCOUNT_ACTIVATION_DAYS`` be supplied, specifying (as an |
79
|
|
|
integer) the number of days from acceptance during which a user may |
80
|
|
|
activate their account (after that period expires, activation will be |
81
|
|
|
disallowed). Default is ``7`` |
82
|
|
|
|
83
|
|
|
* The creation of the templates |
84
|
|
|
|
85
|
|
|
- ``registration/registration_email.txt`` |
86
|
|
|
- ``registration/registration_email_subject.txt`` |
87
|
|
|
- ``registration/acceptance_email.txt`` |
88
|
|
|
- ``registration/acceptance_email_subject.txt`` |
89
|
|
|
- ``registration/rejection_email.txt`` |
90
|
|
|
- ``registration/rejection_email_subject.txt`` |
91
|
|
|
- ``registration/activation_email.txt`` |
92
|
|
|
- ``registration/activation_email_subject.txt`` |
93
|
|
|
|
94
|
|
|
Additinally, registration can be temporarily closed by adding the setting |
95
|
|
|
``REGISTRATION_OPEN`` and setting it to ``False``. Omitting this setting, |
96
|
|
|
or setting it to ``True``, will be imterpreted as meaning that registration |
97
|
|
|
is currently open and permitted. |
98
|
|
|
|
99
|
|
|
Internally, this is accomplished via storing an activation key in an |
100
|
|
|
instance of ``registration.models.RegistrationProfile``. See that model and |
101
|
|
|
its custom manager for full documentation of its fields and supported |
102
|
|
|
operations. |
103
|
|
|
|
104
|
|
|
""" |
105
|
|
|
|
106
|
|
|
def register(self, username, email, request, |
107
|
|
|
supplement=None, send_email=None): |
108
|
|
|
"""register new user with ``username`` and ``email`` |
109
|
|
|
|
110
|
|
|
Given a username, email address, register a new user account, which |
111
|
|
|
will initially be inactive and has unusable password. |
112
|
|
|
|
113
|
|
|
Along with the new ``User`` object, a new |
114
|
|
|
``registration.models.RegistrationProfile`` will be created, tied to |
115
|
|
|
that ``User``, containing the inspection status and activation key |
116
|
|
|
which will be used for this account (activation key is not generated |
117
|
|
|
untill its inspection status is set to ``accepted``) |
118
|
|
|
|
119
|
|
|
An email will be sent to the supplied email address; The email will be |
120
|
|
|
rendered using two templates. See the documentation for |
121
|
|
|
``RegistrationProfile.send_registration_email()`` for information about |
122
|
|
|
these templates and the contexts provided to them. |
123
|
|
|
|
124
|
|
|
If ``REGISTRATION_REGISTRATION_EMAIL`` of settings is ``None``, no |
125
|
|
|
registration email will be sent. |
126
|
|
|
|
127
|
|
|
After the ``User`` and ``RegistrationProfile`` are created and the |
128
|
|
|
registration email is sent, the signal |
129
|
|
|
``registration.signals.user_registered`` will be sent, with the new |
130
|
|
|
``User`` as the keyword argument ``user``, the ``RegistrationProfile`` |
131
|
|
|
of the new ``User`` as the keyword argument ``profile`` and the class |
132
|
|
|
of this backend as the sender. |
133
|
|
|
|
134
|
|
|
""" |
135
|
|
|
if send_email is None: |
136
|
|
|
send_email = settings.REGISTRATION_REGISTRATION_EMAIL |
137
|
|
|
|
138
|
|
|
new_user = RegistrationProfile.objects.register( |
139
|
|
|
username, email, self.get_site(request), |
140
|
|
|
send_email=send_email, |
141
|
|
|
) |
142
|
|
|
profile = new_user.registration_profile |
143
|
|
|
|
144
|
|
|
if supplement: |
145
|
|
|
supplement.registration_profile = profile |
146
|
|
|
supplement.save() |
147
|
|
|
|
148
|
|
|
signals.user_registered.send( |
149
|
|
|
sender=self.__class__, |
150
|
|
|
user=new_user, |
151
|
|
|
profile=new_user.registration_profile, |
152
|
|
|
request=request, |
153
|
|
|
) |
154
|
|
|
|
155
|
|
|
return new_user |
156
|
|
|
|
157
|
|
|
def accept(self, profile, request, send_email=None, message=None, |
158
|
|
|
force=False): |
159
|
|
|
"""accept the account registration of ``profile`` |
160
|
|
|
|
161
|
|
|
Given a profile, accept account registration, which will |
162
|
|
|
set inspection status of ``profile`` to ``accepted`` and generate new |
163
|
|
|
activation key of ``profile``. |
164
|
|
|
|
165
|
|
|
An email will be sent to the supplied email address; The email will be |
166
|
|
|
rendered using two templates. See the documentation for |
167
|
|
|
``RegistrationProfile.send_acceptance_email()`` for information about |
168
|
|
|
these templates and the contexts provided to them. |
169
|
|
|
|
170
|
|
|
If ``REGISTRATION_acceptance_EMAIL`` of settings is ``None``, no |
171
|
|
|
acceptance email will be sent. |
172
|
|
|
|
173
|
|
|
After successful acceptance, the signal |
174
|
|
|
``registration.signals.user_accepted`` will be sent, with the newly |
175
|
|
|
accepted ``User`` as the keyword argument ``uesr``, the |
176
|
|
|
``RegistrationProfile`` of the ``User`` as the keyword argument |
177
|
|
|
``profile`` and the class of this backend as the sender |
178
|
|
|
|
179
|
|
|
""" |
180
|
|
|
if send_email is None: |
181
|
|
|
send_email = settings.REGISTRATION_ACCEPTANCE_EMAIL |
182
|
|
|
|
183
|
|
|
accepted_user = RegistrationProfile.objects.accept_registration( |
184
|
|
|
profile, self.get_site(request), |
185
|
|
|
send_email=send_email, message=message, |
186
|
|
|
force=force, |
187
|
|
|
) |
188
|
|
|
|
189
|
|
|
if accepted_user: |
190
|
|
|
signals.user_accepted.send( |
191
|
|
|
sender=self.__class__, |
192
|
|
|
user=accepted_user, |
193
|
|
|
profile=profile, |
194
|
|
|
request=request, |
195
|
|
|
) |
196
|
|
|
|
197
|
|
|
return accepted_user |
198
|
|
|
|
199
|
|
|
def reject(self, profile, request, send_email=None, message=None): |
200
|
|
|
"""reject the account registration of ``profile`` |
201
|
|
|
|
202
|
|
|
Given a profile, reject account registration, which will |
203
|
|
|
set inspection status of ``profile`` to ``rejected`` and delete |
204
|
|
|
activation key of ``profile`` if exists. |
205
|
|
|
|
206
|
|
|
An email will be sent to the supplied email address; The email will be |
207
|
|
|
rendered using two templates. See the documentation for |
208
|
|
|
``RegistrationProfile.send_rejection_email()`` for information about |
209
|
|
|
these templates and the contexts provided to them. |
210
|
|
|
|
211
|
|
|
If ``REGISTRATION_REJECTION_EMAIL`` of settings is ``None``, no |
212
|
|
|
rejection email will be sent. |
213
|
|
|
|
214
|
|
|
After successful rejection, the signal |
215
|
|
|
``registration.signals.user_rejected`` will be sent, with the newly |
216
|
|
|
rejected ``User`` as the keyword argument ``uesr``, the |
217
|
|
|
``RegistrationProfile`` of the ``User`` as the keyword argument |
218
|
|
|
``profile`` and the class of this backend as the sender |
219
|
|
|
|
220
|
|
|
""" |
221
|
|
|
if send_email is None: |
222
|
|
|
send_email = settings.REGISTRATION_REJECTION_EMAIL |
223
|
|
|
|
224
|
|
|
rejected_user = RegistrationProfile.objects.reject_registration( |
225
|
|
|
profile, self.get_site(request), |
226
|
|
|
send_email=send_email, message=message) |
227
|
|
|
|
228
|
|
|
if rejected_user: |
229
|
|
|
signals.user_rejected.send( |
230
|
|
|
sender=self.__class__, |
231
|
|
|
user=rejected_user, |
232
|
|
|
profile=profile, |
233
|
|
|
request=request, |
234
|
|
|
) |
235
|
|
|
|
236
|
|
|
return rejected_user |
237
|
|
|
|
238
|
|
|
def activate(self, activation_key, request, password=None, send_email=None, |
239
|
|
|
message=None, no_profile_delete=False): |
240
|
|
|
"""activate user with ``activation_key`` and ``password`` |
241
|
|
|
|
242
|
|
|
Given an activation key, password, look up and activate the user |
243
|
|
|
account corresponding to that key (if possible) and set its password. |
244
|
|
|
|
245
|
|
|
If ``password`` is not given, password will be generated |
246
|
|
|
|
247
|
|
|
An email will be sent to the supplied email address; The email will be |
248
|
|
|
rendered using two templates. See the documentation for |
249
|
|
|
``RegistrationProfile.send_activation_email()`` for information about |
250
|
|
|
these templates and the contexts provided to them. |
251
|
|
|
|
252
|
|
|
If ``REGISTRATION_ACTIVATION_EMAIL`` of settings is ``None``, no |
253
|
|
|
activation email will be sent. |
254
|
|
|
|
255
|
|
|
After successful activation, the signal |
256
|
|
|
``registration.signals.user_activated`` will be sent, with the newly |
257
|
|
|
activated ``User`` as the keyword argument ``uesr``, the password |
258
|
|
|
of the ``User`` as the keyword argument ``password``, whether the |
259
|
|
|
password has generated or not as the keyword argument ``is_generated`` |
260
|
|
|
and the class of this backend as the sender |
261
|
|
|
|
262
|
|
|
""" |
263
|
|
|
if send_email is None: |
264
|
|
|
send_email = settings.REGISTRATION_ACTIVATION_EMAIL |
265
|
|
|
|
266
|
|
|
activated = RegistrationProfile.objects.activate_user( |
267
|
|
|
activation_key=activation_key, |
268
|
|
|
site=self.get_site(request), |
269
|
|
|
password=password, |
270
|
|
|
send_email=send_email, |
271
|
|
|
message=message, |
272
|
|
|
no_profile_delete=no_profile_delete) |
273
|
|
|
|
274
|
|
|
if activated: |
275
|
|
|
user, password, is_generated = activated |
276
|
|
|
signals.user_activated.send( |
277
|
|
|
sender=self.__class__, |
278
|
|
|
user=user, |
279
|
|
|
password=password, |
280
|
|
|
is_generated=is_generated, |
281
|
|
|
request=request, |
282
|
|
|
) |
283
|
|
|
return user |
284
|
|
|
return None |
285
|
|
|
|
286
|
|
|
def get_supplement_class(self): |
287
|
|
|
"""Return the current registration supplement class""" |
288
|
|
|
# cache mechanisms will break the test thus disable it in test |
289
|
|
|
if not hasattr(self, '_supplement_class_cache') or 'test' in sys.argv: |
290
|
|
|
cls = get_supplement_class() |
291
|
|
|
setattr(self, '_supplement_class_cache', cls) |
292
|
|
|
return getattr(self, '_supplement_class_cache') |
293
|
|
|
|
294
|
|
|
def get_activation_form_class(self): |
295
|
|
|
"""Return the default form class used for user activation""" |
296
|
|
|
return ActivationForm |
297
|
|
|
|
298
|
|
|
def get_registration_form_class(self): |
299
|
|
|
"""Return the default form class used for user registration""" |
300
|
|
|
return RegistrationForm |
301
|
|
|
|
302
|
|
|
def get_supplement_form_class(self): |
303
|
|
|
""" |
304
|
|
|
Return the default form class used for user registration supplement |
305
|
|
|
""" |
306
|
|
|
supplement_class = self.get_supplement_class() |
307
|
|
|
if not supplement_class: |
308
|
|
|
return None |
309
|
|
|
return supplement_class.get_form_class() |
310
|
|
|
|
311
|
|
|
def get_activation_complete_url(self, user): |
312
|
|
|
"""Return a url to redirect to after successful user activation""" |
313
|
|
|
return reverse('registration_activation_complete') |
314
|
|
|
|
315
|
|
|
def get_registration_complete_url(self, user): |
316
|
|
|
"""Return a url to redirect to after successful user registration""" |
317
|
|
|
return reverse('registration_complete') |
318
|
|
|
|
319
|
|
|
def get_registration_closed_url(self): |
320
|
|
|
"""Return a url to redirect to if registration is closed""" |
321
|
|
|
return reverse('registration_disallowed') |
322
|
|
|
|
323
|
|
|
def registration_allowed(self): |
324
|
|
|
""" |
325
|
|
|
Indicate whether account registration is currently permitted, based on |
326
|
|
|
the value of the setting ``REGISTRATION_OEPN``. This is determined as |
327
|
|
|
follows: |
328
|
|
|
|
329
|
|
|
* If ``REGISTRATION_OPEN`` is not specified in settings, or is set |
330
|
|
|
to ``True``, registration is permitted. |
331
|
|
|
|
332
|
|
|
* If ``REGISTRATION_OPEN`` is both specified and set to ``False``, |
333
|
|
|
registration is not permitted. |
334
|
|
|
|
335
|
|
|
""" |
336
|
|
|
return getattr(settings, 'REGISTRATION_OPEN', True) |
337
|
|
|
|