Revision 0a569195 snf-astakos-app/astakos/im/activation_backends.py
b/snf-astakos-app/astakos/im/activation_backends.py | ||
---|---|---|
46 | 46 |
from astakos.im.models import AstakosUser, Invitation |
47 | 47 |
from astakos.im.forms import * |
48 | 48 |
from astakos.im.util import get_invitation |
49 |
from astakos.im.functions import send_verification, send_admin_notification, activate |
|
49 |
from astakos.im.functions import send_verification, send_admin_notification, activate, SendMailError
|
|
50 | 50 |
from astakos.im.settings import INVITATIONS_ENABLED, DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, MODERATION_ENABLED, SITENAME, DEFAULT_ADMIN_EMAIL, RE_USER_EMAIL_PATTERNS |
51 | 51 |
|
52 | 52 |
import socket |
... | ... | |
78 | 78 |
raise ImproperlyConfigured('Module "%s" does not define a activation backend named "%s"' % (module, attr)) |
79 | 79 |
return backend_class(request) |
80 | 80 |
|
81 |
class SignupBackend(object):
|
|
81 |
class ActivationBackend(object):
|
|
82 | 82 |
def _is_preaccepted(self, user): |
83 | 83 |
# return True if user email matches specific patterns |
84 | 84 |
for pattern in RE_USER_EMAIL_PATTERNS: |
85 | 85 |
if re.match(pattern, user.email): |
86 | 86 |
return True |
87 | 87 |
return False |
88 |
|
|
89 |
def get_signup_form(self, provider='local', instance=None): |
|
90 |
""" |
|
91 |
Returns the form class name |
|
92 |
""" |
|
93 |
main = provider.capitalize() if provider == 'local' else 'ThirdParty' |
|
94 |
suffix = 'UserCreationForm' |
|
95 |
formclass = '%s%s' % (main, suffix) |
|
96 |
request = self.request |
|
97 |
initial_data = None |
|
98 |
if request.method == 'POST': |
|
99 |
if provider == request.POST.get('provider', ''): |
|
100 |
initial_data = request.POST |
|
101 |
return globals()[formclass](initial_data, instance=instance, request=request) |
|
102 |
|
|
103 |
def handle_activation(self, user, \ |
|
104 |
verification_template_name='im/activation_email.txt', \ |
|
105 |
greeting_template_name='im/welcome_email.txt', \ |
|
106 |
admin_email_template_name='im/admin_notification.txt', \ |
|
107 |
switch_accounts_email_template_name='im/switch_accounts_email.txt'): |
|
108 |
""" |
|
109 |
If the user is already active returns immediately. |
|
110 |
If the user is not active and there is another account associated with |
|
111 |
the specific email, it sends an informative email to the user whether |
|
112 |
wants to switch to this account. |
|
113 |
If the user is preaccepted and the email is verified, the account is |
|
114 |
activated automatically. Otherwise, if the email is not verified, |
|
115 |
it sends a verification email to the user. |
|
116 |
If the user is not preaccepted, it sends an email to the administrators |
|
117 |
and informs the user that the account is pending activation. |
|
118 |
""" |
|
119 |
try: |
|
120 |
if user.is_active: |
|
121 |
return RegistationCompleted() |
|
122 |
if user.conflicting_email(): |
|
123 |
send_verification(user, switch_accounts_email_template_name) |
|
124 |
return SwitchAccountsVerificationSent(user.email) |
|
125 |
|
|
126 |
if self._is_preaccepted(user): |
|
127 |
if user.email_verified: |
|
128 |
activate(user, greeting_template_name) |
|
129 |
return RegistationCompleted() |
|
130 |
else: |
|
131 |
send_verification(user, verification_template_name) |
|
132 |
return VerificationSent() |
|
133 |
else: |
|
134 |
send_admin_notification(user, admin_email_template_name) |
|
135 |
return NotificationSent() |
|
136 |
except BaseException, e: |
|
137 |
logger.exception(e) |
|
138 |
raise e |
|
88 | 139 |
|
89 |
class InvitationsBackend(SignupBackend):
|
|
140 |
class InvitationsBackend(ActivationBackend):
|
|
90 | 141 |
""" |
91 | 142 |
A activation backend which implements the following workflow: a user |
92 | 143 |
supplies the necessary registation information, if the request contains a valid |
... | ... | |
95 | 146 |
administrator activates his/her account. |
96 | 147 |
""" |
97 | 148 |
def __init__(self, request): |
98 |
""" |
|
99 |
raises Invitation.DoesNotExist and ValueError if invitation is consumed |
|
100 |
or invitation username is reserved. |
|
101 |
""" |
|
102 | 149 |
self.request = request |
103 | 150 |
super(InvitationsBackend, self).__init__() |
104 | 151 |
|
105 | 152 |
def get_signup_form(self, provider='local', instance=None): |
106 | 153 |
""" |
107 |
Returns the form class name |
|
154 |
Returns the form class |
|
155 |
|
|
156 |
raises Invitation.DoesNotExist and ValueError if invitation is consumed |
|
157 |
or invitation username is reserved. |
|
108 | 158 |
""" |
109 |
try: |
|
110 |
self.invitation = get_invitation(self.request) |
|
111 |
except (Invitation, ValueError), e: |
|
112 |
self.invitation = None |
|
113 |
else: |
|
114 |
invitation = self.invitation |
|
115 |
initial_data = self.get_signup_initial_data(provider) |
|
116 |
prefix = 'Invited' if invitation else '' |
|
117 |
main = provider.capitalize() |
|
118 |
suffix = 'UserCreationForm' |
|
119 |
formclass = '%s%s%s' % (prefix, main, suffix) |
|
120 |
ip = self.request.META.get('REMOTE_ADDR', |
|
121 |
self.request.META.get('HTTP_X_REAL_IP', None)) |
|
122 |
return globals()[formclass](initial_data, instance=instance, ip=ip) |
|
159 |
self.invitation = get_invitation(self.request) |
|
160 |
invitation = self.invitation |
|
161 |
initial_data = self.get_signup_initial_data(provider) |
|
162 |
prefix = 'Invited' if invitation else '' |
|
163 |
main = provider.capitalize() |
|
164 |
suffix = 'UserCreationForm' |
|
165 |
formclass = '%s%s%s' % (prefix, main, suffix) |
|
166 |
return globals()[formclass](initial_data, instance=instance, request=self.request) |
|
123 | 167 |
|
124 | 168 |
def get_signup_initial_data(self, provider): |
125 | 169 |
""" |
... | ... | |
160 | 204 |
return True |
161 | 205 |
return False |
162 | 206 |
|
163 |
def handle_activation(self, user, verification_template_name='im/activation_email.txt', greeting_template_name='im/welcome_email.txt', admin_email_template_name='im/admin_notification.txt'): |
|
164 |
""" |
|
165 |
Initially creates an inactive user account. If the user is preaccepted |
|
166 |
(has a valid invitation code) the user is activated and if the request |
|
167 |
param ``next`` is present redirects to it. |
|
168 |
In any other case the method returns the action status and a message. |
|
169 |
""" |
|
170 |
try: |
|
171 |
if user.is_active: |
|
172 |
return RegistationCompleted() |
|
173 |
if self._is_preaccepted(user): |
|
174 |
if user.email_verified: |
|
175 |
activate(user, greeting_template_name) |
|
176 |
return RegistationCompleted() |
|
177 |
else: |
|
178 |
send_verification(user, verification_template_name) |
|
179 |
return VerificationSent() |
|
180 |
else: |
|
181 |
send_admin_notification(user, admin_email_template_name) |
|
182 |
return NotificationSent() |
|
183 |
except Invitation.DoesNotExist, e: |
|
184 |
raise InvitationCodeError() |
|
185 |
except BaseException, e: |
|
186 |
logger.exception(e) |
|
187 |
raise e |
|
188 |
|
|
189 |
class SimpleBackend(SignupBackend): |
|
207 |
class SimpleBackend(ActivationBackend): |
|
190 | 208 |
""" |
191 | 209 |
A activation backend which implements the following workflow: a user |
192 | 210 |
supplies the necessary registation information, an incative user account is |
... | ... | |
195 | 213 |
def __init__(self, request): |
196 | 214 |
self.request = request |
197 | 215 |
super(SimpleBackend, self).__init__() |
198 |
|
|
199 |
def get_signup_form(self, provider='local', instance=None): |
|
200 |
""" |
|
201 |
Returns the form class name |
|
202 |
""" |
|
203 |
main = provider.capitalize() if provider == 'local' else 'ThirdParty' |
|
204 |
suffix = 'UserCreationForm' |
|
205 |
formclass = '%s%s' % (main, suffix) |
|
206 |
request = self.request |
|
207 |
initial_data = None |
|
208 |
if request.method == 'POST': |
|
209 |
if provider == request.POST.get('provider', ''): |
|
210 |
initial_data = request.POST |
|
211 |
return globals()[formclass](initial_data, instance=instance, request=request) |
|
212 | 216 |
|
213 | 217 |
def _is_preaccepted(self, user): |
214 | 218 |
if super(SimpleBackend, self)._is_preaccepted(user): |
... | ... | |
216 | 220 |
if MODERATION_ENABLED: |
217 | 221 |
return False |
218 | 222 |
return True |
219 |
|
|
220 |
def handle_activation(self, user, email_template_name='im/activation_email.txt', admin_email_template_name='im/admin_notification.txt'): |
|
221 |
""" |
|
222 |
Creates an inactive user account and sends a verification email. |
|
223 |
|
|
224 |
** Arguments ** |
|
225 |
|
|
226 |
``email_template_name`` |
|
227 |
A custom template for the verification email body to use. This is |
|
228 |
optional; if not specified, this will default to |
|
229 |
``im/activation_email.txt``. |
|
230 |
|
|
231 |
** Templates ** |
|
232 |
im/activation_email.txt or ``email_template_name`` keyword argument |
|
233 |
|
|
234 |
** Settings ** |
|
235 |
|
|
236 |
* DEFAULT_CONTACT_EMAIL: service support email |
|
237 |
* DEFAULT_FROM_EMAIL: from email |
|
238 |
""" |
|
239 |
try: |
|
240 |
if user.is_active: |
|
241 |
return RegistrationCompeted() |
|
242 |
if not self._is_preaccepted(user): |
|
243 |
send_admin_notification(user, admin_email_template_name) |
|
244 |
return NotificationSent() |
|
245 |
else: |
|
246 |
send_verification(user, email_template_name) |
|
247 |
return VerificationSend() |
|
248 |
except SendEmailError, e: |
|
249 |
transaction.rollback() |
|
250 |
raise e |
|
251 |
except BaseException, e: |
|
252 |
logger.exception(e) |
|
253 |
raise e |
|
254 |
else: |
|
255 |
transaction.commit() |
|
256 | 223 |
|
257 | 224 |
class ActivationResult(object): |
258 | 225 |
def __init__(self, message): |
... | ... | |
263 | 230 |
message = _('Verification sent.') |
264 | 231 |
super(VerificationSent, self).__init__(message) |
265 | 232 |
|
233 |
class SwitchAccountsVerificationSent(ActivationResult): |
|
234 |
def __init__(self, email): |
|
235 |
message = _('This email is already associated with another \ |
|
236 |
local account. To change this account to a shibboleth \ |
|
237 |
one follow the link in the verification email sent \ |
|
238 |
to %s. Otherwise just ignore it.' % email) |
|
239 |
super(SwitchAccountsVerificationSent, self).__init__(message) |
|
240 |
|
|
266 | 241 |
class NotificationSent(ActivationResult): |
267 | 242 |
def __init__(self): |
268 | 243 |
message = _('Your request for an account was successfully received and is now pending \ |
Also available in: Unified diff