Revision e7cb4085

b/snf-astakos-app/astakos/im/activation_backends.py
37 37

  
38 38
from astakos.im.models import AstakosUser
39 39
from astakos.im.util import get_invitation
40
from astakos.im.functions import (
41
    send_activation, send_account_creation_notification, activate)
42
from astakos.im.settings import (
43
    INVITATIONS_ENABLED, RE_USER_EMAIL_PATTERNS)
44
from astakos.im import settings as astakos_settings
45
from astakos.im.forms import *
40
from astakos.im import functions
41
from astakos.im import settings
42
from astakos.im import forms
43

  
44
from astakos.im.quotas import (qh_sync_user, qh_sync_users,
45
                               register_pending_apps)
46 46

  
47 47
import astakos.im.messages as astakos_messages
48 48

  
49
import datetime
49 50
import logging
50 51
import re
52
import json
51 53

  
52 54
logger = logging.getLogger(__name__)
53 55

  
54 56

  
55
def get_backend(request):
57
def get_backend():
56 58
    """
57 59
    Returns an instance of an activation backend,
58 60
    according to the INVITATIONS_ENABLED setting
......
64 66
    ``django.core.exceptions.ImproperlyConfigured`` is raised.
65 67
    """
66 68
    module = 'astakos.im.activation_backends'
67
    prefix = 'Invitations' if INVITATIONS_ENABLED else 'Simple'
69
    prefix = 'Invitations' if settings.INVITATIONS_ENABLED else 'Simple'
68 70
    backend_class_name = '%sBackend' % prefix
69 71
    try:
70 72
        mod = import_module(module)
......
77 79
        raise ImproperlyConfigured(
78 80
            'Module "%s" does not define a activation backend named "%s"' % (
79 81
                module, backend_class_name))
80
    return backend_class(request)
82
    return backend_class(settings.MODERATION_ENABLED)
81 83

  
82 84

  
83 85
class ActivationBackend(object):
84
    def __init__(self, request):
85
        self.request = request
86
    """
87
    ActivationBackend handles user verification/activation.
88

  
89
    Example usage::
90
    >>> # it is wise to not instantiate a backend class directly but use
91
    >>> # get_backend method instead.
92
    >>> backend = get_backend()
93
    >>> formCls = backend.get_signup_form(request.POST)
94
    >>> if form.is_valid():
95
    >>>     user = form.save(commit=False)
96
    >>>     # this creates auth provider objects
97
    >>>     form.store_user(user)
98
    >>>     activation = backend.handle_registration(user)
99
    >>>     # activation.status is one of backend.Result.{*} activation result
100
    >>>     # types
101
    >>>
102
    >>>     # sending activation notifications is not done automatically
103
    >>>     # we need to call send_result_notifications
104
    >>>     backend.send_result_notifications(activation)
105
    >>>     return HttpResponse(activation.message)
106
    """
107

  
108
    verification_template_name = 'im/activation_email.txt'
109
    greeting_template_name = 'im/welcome_email.txt'
110
    pending_moderation_template_name = \
111
        'im/account_pending_moderation_notification.txt'
112
    activated_email_template_name = 'im/account_activated_notification.txt'
113

  
114
    class Result:
115
        # user created, email verification sent
116
        PENDING_VERIFICATION = 1
117
        # email verified
118
        PENDING_MODERATION = 2
119
        # user moderated
120
        ACCEPTED = 3
121
        # user rejected
122
        REJECTED = 4
123
        # inactive user activated
124
        ACTIVATED = 5
125
        # active user deactivated
126
        DEACTIVATED = 6
127
        # something went wrong
128
        ERROR = -1
129

  
130
    def __init__(self, moderation_enabled):
131
        self.moderation_enabled = moderation_enabled
86 132

  
87 133
    def _is_preaccepted(self, user):
88
        # return True if user email matches specific patterns
89
        for pattern in RE_USER_EMAIL_PATTERNS:
134
        """
135
        Decide whether user should be automatically moderated. The method gets
136
        called only when self.moderation_enabled is set to True.
137

  
138
        The method returns False or a string identifier which later will be
139
        stored in user's accepted_policy field. This is helpfull for
140
        administrators to be aware of the reason a created user was
141
        automatically activated.
142
        """
143

  
144
        # check preaccepted mail patterns
145
        for pattern in settings.RE_USER_EMAIL_PATTERNS:
90 146
            if re.match(pattern, user.email):
91
                return True
147
                return 'email'
148

  
149
        # provider automoderate policy is on
150
        if user.get_auth_provider().get_automoderate_policy:
151
            return 'auth_provider_%s' % user.get_auth_provider().module
152

  
92 153
        return False
93 154

  
94
    def get_signup_form(self, provider='local', instance=None):
155
    def get_signup_form(self, provider='local', initial_data=None, **kwargs):
95 156
        """
96
        Returns a form instance of the relevant class
157
        Returns a form instance for the type of registration the user chosen.
158
        This can be either a LocalUserCreationForm for classic method signups
159
        or ThirdPartyUserCreationForm for users who chosen to signup using a
160
        federated login method.
97 161
        """
98 162
        main = provider.capitalize() if provider == 'local' else 'ThirdParty'
99 163
        suffix = 'UserCreationForm'
100
        formclass = '%s%s' % (main, suffix)
101
        request = self.request
102
        initial_data = None
103
        if request.method == 'POST':
104
            if provider == request.POST.get('provider', ''):
105
                initial_data = request.POST
106
        return globals()[formclass](initial_data, instance=instance, request=request)
107

  
108
    def handle_activation(
109
        self, user, activation_template_name='im/activation_email.txt',
110
        greeting_template_name='im/welcome_email.txt',
111
        admin_email_template_name='im/account_creation_notification.txt',
112
        helpdesk_email_template_name='im/helpdesk_notification.txt'
113
    ):
114
        """
115
        If the user is already active returns immediately.
116
        If the user is preaccepted and the email is verified, the account is
117
        activated automatically. Otherwise, if the email is not verified,
118
        it sends a verification email to the user.
119
        If the user is not preaccepted, it sends an email to the administrators
120
        and informs the user that the account is pending activation.
121
        """
122
        try:
123
            if user.is_active:
124
                return RegistationCompleted()
125

  
126
            if self._is_preaccepted(user):
127
                if user.email_verified:
128
                    activate(
129
                        user,
130
                        greeting_template_name,
131
                        helpdesk_email_template_name
132
                    )
133
                    return RegistationCompleted()
134
                else:
135
                    send_activation(
136
                        user,
137
                        activation_template_name
138
                    )
139
                    return VerificationSent()
140
            else:
141
                send_account_creation_notification(
142
                    template_name=admin_email_template_name,
143
                    dictionary={'user': user, 'group_creation': True}
144
                )
145
                return NotificationSent()
146
        except BaseException, e:
147
            logger.exception(e)
148
            raise e
164
        formclass = getattr(forms, '%s%s' % (main, suffix))
165
        kwargs['provider'] = provider
166
        return formclass(initial_data, **kwargs)
167

  
168
    def prepare_user(self, user, email_verified=None):
169
        """
170
        Initialization of a newly registered user. The method sets email
171
        verification code. If email_verified is set to True we automatically
172
        process user through the verification step.
173
        """
174
        logger.info("Initializing user registration %s", user.log_display)
175

  
176
        if not email_verified:
177
            email_verified = settings.SKIP_EMAIL_VERIFICATION
178

  
179
        user.renew_verification_code()
180
        user.save()
181

  
182
        if email_verified:
183
            logger.info("Auto verifying user email. %s",
184
                        user.log_display)
185
            return self.verify_user(user,
186
                                    user.verification_code)
187

  
188
        return ActivationResult(self.Result.PENDING_VERIFICATION)
189

  
190
    def verify_user(self, user, verification_code):
191
        """
192
        Process user verification using provided verification_code. This
193
        should take place in user activation view. If no moderation is enabled
194
        we automatically process user through activation process.
195
        """
196
        logger.info("Verifying user: %s", user.log_display)
197

  
198
        if user.email_verified:
199
            logger.warning("User email already verified: %s",
200
                           user.log_display)
201
            msg = astakos_messages.ACCOUNT_ALREADY_VERIFIED
202
            return ActivationResult(self.Result.ERROR, msg)
203

  
204
        if user.verification_code and \
205
                user.verification_code == verification_code:
206
            user.email_verified = True
207
            user.verified_at = datetime.datetime.now()
208
            # invalidate previous code
209
            user.renew_verification_code()
210
            user.save()
211
            logger.info("User email verified: %s", user.log_display)
212
        else:
213
            logger.error("User email verification failed "
214
                         "(invalid verification code): %s", user.log_display)
215
            msg = astakos_messages.VERIFICATION_FAILED
216
            return ActivationResult(self.Result.ERROR, msg)
217

  
218
        if not self.moderation_enabled:
219
            logger.warning("User preaccepted (%s): %s", 'auto_moderation',
220
                           user.log_display)
221
            return self.accept_user(user, policy='auto_moderation')
222

  
223
        preaccepted = self._is_preaccepted(user)
224
        if preaccepted:
225
            logger.warning("User preaccepted (%s): %s", preaccepted,
226
                           user.log_display)
227
            return self.accept_user(user, policy=preaccepted)
228

  
229
        if user.moderated:
230
            # set moderated to false because accept_user will return error
231
            # result otherwise.
232
            user.moderated = False
233
            return self.accept_user(user, policy='already_moderated')
234
        else:
235
            return ActivationResult(self.Result.PENDING_MODERATION)
236

  
237
    def accept_user(self, user, policy='manual'):
238
        logger.info("Moderating user: %s", user.log_display)
239
        if user.moderated and user.is_active:
240
            logger.warning("User already accepted, moderation"
241
                           " skipped: %s", user.log_display)
242
            msg = _(astakos_messages.ACCOUNT_ALREADY_MODERATED)
243
            return ActivationResult(self.Result.ERROR, msg)
244

  
245
        if not user.email_verified:
246
            logger.warning("Cannot accept unverified user: %s",
247
                           user.log_display)
248
            msg = _(astakos_messages.ACCOUNT_NOT_VERIFIED)
249
            return ActivationResult(self.Result.ERROR, msg)
250

  
251
        # store a snapshot of user details by the time he
252
        # got accepted.
253
        if not user.accepted_email:
254
            user.accepted_email = user.email
255
        user.accepted_policy = policy
256
        user.moderated = True
257
        user.moderated_at = datetime.datetime.now()
258
        user.moderated_data = json.dumps(user.__dict__,
259
                                         default=lambda obj:
260
                                         str(obj))
261
        user.save()
262
        qh_sync_user(user)
263

  
264
        if user.is_rejected:
265
            logger.warning("User has previously been "
266
                           "rejected, reseting rejection state: %s",
267
                           user.log_display)
268
            user.is_rejected = False
269
            user.rejected_at = None
270

  
271
        user.save()
272
        logger.info("User accepted: %s", user.log_display)
273
        self.activate_user(user)
274
        return ActivationResult(self.Result.ACCEPTED)
275

  
276
    def activate_user(self, user):
277
        if not user.email_verified:
278
            msg = _(astakos_messages.ACCOUNT_NOT_VERIFIED)
279
            return ActivationResult(self.Result.ERROR, msg)
280

  
281
        if not user.moderated:
282
            msg = _(astakos_messages.ACCOUNT_NOT_MODERATED)
283
            return ActivationResult(self.Result.ERROR, msg)
284

  
285
        if user.is_rejected:
286
            msg = _(astakos_messages.ACCOUNT_REJECTED)
287
            return ActivationResult(self.Result.ERROR, msg)
288

  
289
        if user.is_active:
290
            msg = _(astakos_messages.ACCOUNT_ALREADY_ACTIVE)
291
            return ActivationResult(self.Result.ERROR, msg)
292

  
293
        user.is_active = True
294
        user.deactivated_reason = None
295
        user.deactivated_at = None
296
        user.save()
297
        logger.info("User activated: %s", user.log_display)
298
        return ActivationResult(self.Result.ACTIVATED)
299

  
300
    def deactivate_user(self, user, reason=''):
301
        user.is_active = False
302
        user.deactivated_reason = reason
303
        if user.is_active:
304
            user.deactivated_at = datetime.datetime.now()
305
        user.save()
306
        logger.info("User deactivated: %s", user.log_display)
307
        return ActivationResult(self.Result.DEACTIVATED)
308

  
309
    def reject_user(self, user, reason):
310
        logger.info("Rejecting user: %s", user.log_display)
311
        if user.moderated:
312
            logger.warning("User already moderated: %s", user.log_display)
313
            msg = _(astakos_messages.ACCOUNT_ALREADY_MODERATED)
314
            return ActivationResult(self.Result.ERROR, msg)
315

  
316
        if user.is_active:
317
            logger.warning("Cannot reject unverified user: %s",
318
                           user.log_display)
319
            msg = _(astakos_messages.ACCOUNT_NOT_VERIFIED)
320
            return ActivationResult(self.Result.ERROR, msg)
321

  
322
        if not user.email_verified:
323
            logger.warning("Cannot reject unverified user: %s",
324
                           user.log_display)
325
            msg = _(astakos_messages.ACCOUNT_NOT_VERIFIED)
326
            return ActivationResult(self.Result.ERROR, msg)
327

  
328
        user.moderated = True
329
        user.moderated_at = datetime.datetime.now()
330
        user.moderated_data = json.dumps(user.__dict__,
331
                                         default=lambda obj:
332
                                         str(obj))
333
        user.is_rejected = True
334
        user.rejected_reason = reason
335
        logger.info("User rejected: %s", user.log_display)
336
        return ActivationResult(self.Result.REJECTED)
337

  
338
    def handle_registration(self, user, email_verified=False):
339
        logger.info("Handling new user registration: %s", user.log_display)
340
        return self.prepare_user(user, email_verified=email_verified)
341

  
342
    def handle_verification(self, user, activation_code):
343
        logger.info("Handling user email verirfication: %s", user.log_display)
344
        return self.verify_user(user, activation_code)
345

  
346
    def handle_moderation(self, user, accept=True, reject_reason=None):
347
        logger.info("Handling user moderation (%r): %s",
348
                    accept, user.log_display)
349
        if accept:
350
            return self.accept_user(user)
351
        else:
352
            return self.reject_user(user, reject_reason)
353

  
354
    def send_user_verification_email(self, user):
355
        if user.is_active:
356
            raise Exception("User already active")
357

  
358
        # invalidate previous code
359
        user.renew_verification_code()
360
        user.save()
361
        functions.send_verification(user)
362
        user.activation_sent = datetime.datetime.now()
363
        user.save()
364

  
365
    def send_result_notifications(self, result, user):
366
        """
367
        Send corresponding notifications based on the status of activation
368
        result.
369

  
370
        Result.PENDING_VERIRFICATION
371
            * Send user the email verification url
372

  
373
        Result.PENDING_MODERATION
374
            * Notify admin for account moderation
375

  
376
        Result.ACCEPTED
377
            * Send user greeting notification
378

  
379
        Result.REJECTED
380
            * Send nothing
381
        """
382
        if result.status == self.Result.PENDING_VERIFICATION:
383
            logger.info("Sending notifications for user"
384
                        " creation: %s", user.log_display)
385
            # email user that contains the activation link
386
            self.send_user_verification_email(user)
387
            # TODO: optionally notify admins for new accounts
388

  
389
        if result.status == self.Result.PENDING_MODERATION:
390
            logger.info("Sending notifications for user"
391
                        " verification: %s", user.log_display)
392
            functions.send_account_pending_moderation_notification(user,
393
                                        self.pending_moderation_template_name)
394
            # TODO: notify user
395

  
396
        if result.status == self.Result.ACCEPTED:
397
            logger.info("Sending notifications for user"
398
                        " moderation: %s", user.log_display)
399
            functions.send_account_activated_notification(user,
400
                                         self.activated_email_template_name)
401
            functions.send_greeting(user,
402
                                    self.greeting_template_name)
403
            # TODO: notify admins
404

  
405
        if result.status == self.Result.REJECTED:
406
            logger.info("Sending notifications for user"
407
                        " rejection: %s", user.log_display)
408
            # TODO: notify user and admins
149 409

  
150 410

  
151 411
class InvitationsBackend(ActivationBackend):
152 412
    """
153 413
    A activation backend which implements the following workflow: a user
154
    supplies the necessary registation information, if the request contains a valid
155
    inivation code the user is automatically activated otherwise an inactive user
156
    account is created and the user is going to receive an email as soon as an
157
    administrator activates his/her account.
414
    supplies the necessary registation information, if the request contains a
415
    valid inivation code the user is automatically activated otherwise an
416
    inactive user account is created and the user is going to receive an email
417
    as soon as an administrator activates his/her account.
158 418
    """
159 419

  
160
    def get_signup_form(self, provider='local', instance=None):
420
    def get_signup_form(self, invitation, provider='local', inital_data=None,
421
                        instance=None):
161 422
        """
162 423
        Returns a form instance of the relevant class
163 424

  
164 425
        raises Invitation.DoesNotExist and ValueError if invitation is consumed
165 426
        or invitation username is reserved.
166 427
        """
167
        self.invitation = get_invitation(self.request)
168
        invitation = self.invitation
169
        initial_data = self.get_signup_initial_data(provider)
428
        self.invitation = invitation
170 429
        prefix = 'Invited' if invitation else ''
171 430
        main = provider.capitalize() if provider == 'local' else 'ThirdParty'
172 431
        suffix = 'UserCreationForm'
173
        formclass = '%s%s%s' % (prefix, main, suffix)
174
        return globals()[formclass](initial_data, instance=instance, request=self.request)
432
        formclass = getattr(forms, '%s%s%s' % (prefix, main, suffix))
433
        return formclass(initial_data, instance=instance)
175 434

  
176
    def get_signup_initial_data(self, provider):
435
    def get_signup_initial_data(self, request, provider):
177 436
        """
178
        Returns the necassary activation form depending the user is invited or not
437
        Returns the necassary activation form depending the user is invited or
438
        not.
179 439

  
180 440
        Throws Invitation.DoesNotExist in case ``code`` is not valid.
181 441
        """
182
        request = self.request
183 442
        invitation = self.invitation
184 443
        initial_data = None
185 444
        if request.method == 'GET':
......
199 458

  
200 459
    def _is_preaccepted(self, user):
201 460
        """
202
        Extends _is_preaccepted and if there is a valid, not-consumed invitation
203
        code for the specific user returns True else returns False.
461
        Extends _is_preaccepted and if there is a valid, not-consumed
462
        invitation code for the specific user returns True else returns False.
204 463
        """
205
        if super(InvitationsBackend, self)._is_preaccepted(user):
206
            return True
464
        preaccepted = super(InvitationsBackend, self)._is_preaccepted(user)
465
        if preaccepted:
466
            return preaccepted
207 467
        invitation = self.invitation
208 468
        if not invitation:
209
            return not astakos_settings.MODERATION_ENABLED
469
            if not self.moderation_enabled:
470
                return 'auto_moderation'
210 471
        if invitation.username == user.email and not invitation.is_consumed:
211 472
            invitation.consume()
212
            return True
473
            return 'invitation'
213 474
        return False
214 475

  
215 476

  
216 477
class SimpleBackend(ActivationBackend):
217 478
    """
218
    A activation backend which implements the following workflow: a user
219
    supplies the necessary registation information, an incative user account is
220
    created and receives an email in order to activate his/her account.
479
    The common activation backend.
221 480
    """
222
    def _is_preaccepted(self, user):
223
        if super(SimpleBackend, self)._is_preaccepted(user):
224
            return True
225 481

  
226
        return user.get_auth_provider().get_automoderate_policy
482
# shortcut
483
ActivationResultStatus = ActivationBackend.Result
227 484

  
228 485

  
229 486
class ActivationResult(object):
230
    def __init__(self, message):
231
        self.message = message
232 487

  
488
    MESSAGE_BY_STATUS = {
489
        ActivationResultStatus.PENDING_VERIFICATION:
490
        _(astakos_messages.VERIFICATION_SENT),
491
        ActivationResultStatus.PENDING_MODERATION:
492
        _(astakos_messages.NOTIFICATION_SENT),
493
        ActivationResultStatus.ACCEPTED:
494
        _(astakos_messages.ACCOUNT_ACTIVATED),
495
        ActivationResultStatus.ACTIVATED:
496
        _(astakos_messages.ACCOUNT_ACTIVATED),
497
        ActivationResultStatus.DEACTIVATED:
498
        _(astakos_messages.ACCOUNT_DEACTIVATED),
499
        ActivationResultStatus.ERROR:
500
        _(astakos_messages.GENERIC_ERROR)
501
    }
502

  
503
    STATUS_DISPLAY = {
504
        ActivationResultStatus.PENDING_VERIFICATION: 'PENDING_VERIFICATION',
505
        ActivationResultStatus.PENDING_MODERATION: 'PENDING_MODERATION',
506
        ActivationResultStatus.ACCEPTED: 'ACCEPTED',
507
        ActivationResultStatus.ACTIVATED: 'ACTIVATED',
508
        ActivationResultStatus.DEACTIVATED: 'DEACTIVATED',
509
        ActivationResultStatus.ERROR: 'ERROR'
510
    }
233 511

  
234
class VerificationSent(ActivationResult):
235
    def __init__(self):
236
        message = _(astakos_messages.VERIFICATION_SENT)
237
        super(VerificationSent, self).__init__(message)
512
    def __init__(self, status, message=None):
513
        if message is None:
514
            message = self.MESSAGE_BY_STATUS.get(status)
515

  
516
        self.message = message
517
        self.status = status
238 518

  
239
class NotificationSent(ActivationResult):
240
    def __init__(self):
241
        message = _(astakos_messages.NOTIFICATION_SENT)
242
        super(NotificationSent, self).__init__(message)
519
    def status_display(self):
520
        return self.STATUS_DISPLAY.get(self.status)
243 521

  
522
    def __repr__(self):
523
        return "ActivationResult [%s]: %s" % (self.status_display(),
524
                                              self.message)
244 525

  
245
class RegistationCompleted(ActivationResult):
246
    def __init__(self):
247
        message = _(astakos_messages.REGISTRATION_COMPLETED)
248
        super(RegistationCompleted, self).__init__(message)
526
    def is_error(self):
527
        return self.status == ActivationResultStatus.ERROR
b/snf-astakos-app/astakos/im/forms.py
87 87
    r'^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$',
88 88
    re.IGNORECASE)
89 89

  
90

  
90 91
class StoreUserMixin(object):
91 92

  
92
    def store_user(self, user, request):
93
    def store_user(self, user, request=None):
93 94
        """
94 95
        WARNING: this should be wrapped inside a transactional view/method.
95 96
        """
......
128 129
        Changes the order of fields, and removes the username field.
129 130
        """
130 131
        request = kwargs.pop('request', None)
132
        provider = kwargs.pop('provider', 'local')
133

  
134
        # we only use LocalUserCreationForm for local provider
135
        if not provider == 'local':
136
            raise Exception('Invalid provider')
137

  
131 138
        if request:
132 139
            self.ip = request.META.get('REMOTE_ADDR',
133
                                       request.META.get('HTTP_X_REAL_IP', None))
140
                                       request.META.get('HTTP_X_REAL_IP',
141
                                                        None))
134 142

  
135 143
        super(LocalUserCreationForm, self).__init__(*args, **kwargs)
136 144
        self.fields.keyOrder = ['email', 'first_name', 'last_name',
......
181 189
        if not check.is_valid:
182 190
            raise forms.ValidationError(_(astakos_messages.CAPTCHA_VALIDATION_ERR))
183 191

  
184
    def post_store_user(self, user, request):
192
    def post_store_user(self, user, request=None):
185 193
        """
186 194
        Interface method for descendant backends to be able to do stuff within
187 195
        the transaction enabled by store_user.
......
195 203
        save behavior is complete.
196 204
        """
197 205
        user = super(LocalUserCreationForm, self).save(commit=False)
206
        user.date_signed_terms = datetime.now()
198 207
        user.renew_token()
199 208
        if commit:
200 209
            user.save()
201
            logger.log(LOGGING_LEVEL, 'Created user %s' % user.email)
210
            logger.info('Created user %s', user.log_display)
202 211
        return user
203 212

  
204 213

  
......
231 240

  
232 241

  
233 242
class ThirdPartyUserCreationForm(forms.ModelForm, StoreUserMixin):
234
    id = forms.CharField(
235
        widget=forms.HiddenInput(),
236
        label='',
237
        required=False
238
    )
239
    third_party_identifier = forms.CharField(
240
        widget=forms.HiddenInput(),
241
        label=''
242
    )
243 243
    email = forms.EmailField(
244 244
        label='Contact email',
245
        help_text = 'This is needed for contact purposes. ' \
246
        'It doesn't need to be the same with the one you ' \
245
        help_text='This is needed for contact purposes. '
246
        'It doesn't need to be the same with the one you '
247 247
        'provided to login previously. '
248 248
    )
249 249

  
250 250
    class Meta:
251 251
        model = AstakosUser
252
        fields = ['id', 'email', 'third_party_identifier',
253
                  'first_name', 'last_name', 'has_signed_terms']
252
        fields = ['email', 'first_name', 'last_name', 'has_signed_terms']
254 253

  
255 254
    def __init__(self, *args, **kwargs):
256 255
        """
257 256
        Changes the order of fields, and removes the username field.
258 257
        """
259
        self.request = kwargs.get('request', None)
260
        if self.request:
261
            kwargs.pop('request')
258

  
259
        self.provider = kwargs.pop('provider', None)
260
        if not self.provider or self.provider == 'local':
261
            raise Exception('Invalid provider, %r' % self.provider)
262

  
263
        # ThirdPartyUserCreationForm should always get instantiated with
264
        # a third_party_token value
265
        self.third_party_token = kwargs.pop('third_party_token', None)
266
        if not self.third_party_token:
267
            raise Exception('ThirdPartyUserCreationForm'
268
                            ' requires third_party_token')
262 269

  
263 270
        super(ThirdPartyUserCreationForm, self).__init__(*args, **kwargs)
264 271

  
......
278 285
        if not email:
279 286
            raise forms.ValidationError(_(astakos_messages.REQUIRED_FIELD))
280 287
        if reserved_verified_email(email):
281
            provider_id = self.request.REQUEST.get('provider', 'local')
288
            provider_id = self.provider
282 289
            provider = auth_providers.get_provider(provider_id)
283 290
            extra_message = provider.get_add_to_existing_account_msg
284 291

  
285
            raise forms.ValidationError(mark_safe(_(astakos_messages.EMAIL_USED) + ' ' +
286
                                        extra_message))
292
            raise forms.ValidationError(mark_safe(
293
                _(astakos_messages.EMAIL_USED) + ' ' + extra_message))
287 294
        return email
288 295

  
289 296
    def clean_has_signed_terms(self):
......
292 299
            raise forms.ValidationError(_(astakos_messages.SIGN_TERMS))
293 300
        return has_signed_terms
294 301

  
295
    def post_store_user(self, user, request):
296
        pending = PendingThirdPartyUser.objects.get(
297
            token=request.POST.get('third_party_token'),
298
            third_party_identifier=
299
            self.cleaned_data.get('third_party_identifier'))
302
    def _get_pending_user(self):
303
        return PendingThirdPartyUser.objects.get(token=self.third_party_token)
304

  
305
    def post_store_user(self, user, request=None):
306
        pending = self._get_pending_user()
300 307
        provider = pending.get_provider(user)
301 308
        provider.add_to_user()
302 309
        pending.delete()
......
305 312
        user = super(ThirdPartyUserCreationForm, self).save(commit=False)
306 313
        user.set_unusable_password()
307 314
        user.renew_token()
315
        user.date_signed_terms = datetime.now()
308 316
        if commit:
309 317
            user.save()
310
            logger.log(LOGGING_LEVEL, 'Created user %s' % user.email)
318
            logger.info('Created user %s' % user.log_display)
311 319
        return user
312 320

  
313 321

  
......
409 417
                user = AstakosUser.objects.get_by_identifier(username)
410 418
                if not user.has_auth_provider('local'):
411 419
                    provider = auth_providers.get_provider('local', user)
412
                    raise forms.ValidationError(
413
                        provider.get_login_disabled_msg)
420
                    msg = provider.get_login_disabled_msg
421
                    raise forms.ValidationError(mark_safe(msg))
414 422
            except AstakosUser.DoesNotExist:
415 423
                pass
416 424

  
......
515 523
            user = AstakosUser.objects.get_by_identifier(email)
516 524
            self.users_cache = [user]
517 525
            if not user.is_active:
518
                raise forms.ValidationError(user.get_inactive_message('local'))
526
                msg = mark_safe(user.get_inactive_message('local'))
527
                raise forms.ValidationError(msg)
519 528

  
520 529
            provider = auth_providers.get_provider('local', user)
521 530
            if not user.has_usable_password():
522 531
                msg = provider.get_unusable_password_msg
523
                raise forms.ValidationError(msg)
532
                raise forms.ValidationError(mark_safe(msg))
524 533

  
525 534
            if not user.can_change_password():
526 535
                msg = provider.get_cannot_change_password_msg
527
                raise forms.ValidationError(msg)
536
                raise forms.ValidationError(mark_safe(msg))
528 537

  
529 538
        except AstakosUser.DoesNotExist:
530 539
            raise forms.ValidationError(_(astakos_messages.EMAIL_UNKNOWN))
......
597 606
            raise forms.ValidationError(_(astakos_messages.SIGN_TERMS))
598 607
        return has_signed_terms
599 608

  
609
    def save(self, commit=True):
610
        user = super(SignApprovalTermsForm, self).save(commit)
611
        user.date_signed_terms = datetime.now()
612
        if commit:
613
            user.save()
614
        return user
615

  
600 616

  
601 617
class InvitationForm(forms.ModelForm):
602 618

  
b/snf-astakos-app/astakos/im/functions.py
61 61
    EMAIL_CHANGE_EMAIL_SUBJECT,
62 62
    PROJECT_CREATION_SUBJECT, PROJECT_APPROVED_SUBJECT,
63 63
    PROJECT_TERMINATION_SUBJECT, PROJECT_SUSPENSION_SUBJECT,
64
    PROJECT_MEMBERSHIP_CHANGE_SUBJECT,
65
    )
64
    PROJECT_MEMBERSHIP_CHANGE_SUBJECT)
66 65
from astakos.im.notifications import build_notification, NotificationError
67 66
from astakos.im.models import (
68 67
    AstakosUser, Invitation, ProjectMembership, ProjectApplication, Project,
69 68
    UserSetting,
70 69
    get_resource_names, new_chain)
71
from astakos.im.quotas import (qh_sync_user, qh_sync_project,
72
                               register_pending_apps)
70
from astakos.im.quotas import (qh_sync_user, qh_sync_users,
71
                               register_pending_apps, qh_sync_project)
73 72
from astakos.im.project_notif import (
74 73
    membership_change_notify, membership_enroll_notify,
75 74
    membership_request_notify, membership_leave_request_notify,
......
101 100
def send_verification(user, template_name='im/activation_email.txt'):
102 101
    """
103 102
    Send email to user to verify his/her email and activate his/her account.
104

  
105
    Raises SendVerificationError
106 103
    """
107
    url = '%s?auth=%s&next=%s' % (join_urls(BASEURL, reverse('activate')),
108
                                  quote(user.auth_token),
109
                                  quote(join_urls(BASEURL, reverse('index'))))
104
    url = join_urls(BASEURL, user.get_activation_url(nxt=reverse('index')))
110 105
    message = render_to_string(template_name, {
111 106
                               'user': user,
112 107
                               'url': url,
......
114 109
                               'site_name': SITENAME,
115 110
                               'support': CONTACT_EMAIL})
116 111
    sender = settings.SERVER_EMAIL
117
    try:
118
        send_mail(_(VERIFICATION_EMAIL_SUBJECT), message, sender, [user.email],
119
                  connection=get_connection())
120

  
121
    except (SMTPException, socket.error) as e:
122
        logger.exception(e)
123
        raise SendVerificationError()
124
    else:
125
        msg = 'Sent activation %s' % user.email
126
        logger.log(LOGGING_LEVEL, msg)
127

  
128

  
129
def send_activation(user, template_name='im/activation_email.txt'):
130
    send_verification(user, template_name)
131
    user.activation_sent = datetime.now()
132
    user.save()
112
    send_mail(_(VERIFICATION_EMAIL_SUBJECT), message, sender, [user.email],
113
              connection=get_connection())
114
    logger.info("Sent user verirfication email: %s", user.log_display)
133 115

  
134 116

  
135 117
def _send_admin_notification(template_name,
136
                             dictionary=None,
118
                             context=None,
119
                             user=None,
120
                             msg="",
137 121
                             subject='alpha2 testing notification',):
138 122
    """
139
    Send notification email to settings.HELPDESK + settings.MANAGERS.
140

  
141
    Raises SendNotificationError
123
    Send notification email to settings.HELPDESK + settings.MANAGERS +
124
    settings.ADMINS.
142 125
    """
143
    dictionary = dictionary or {}
144
    message = render_to_string(template_name, dictionary)
126
    if context is None:
127
        context = {}
128
    if not 'user' in context:
129
        context['user'] = user
130

  
131
    message = render_to_string(template_name, context)
145 132
    sender = settings.SERVER_EMAIL
146
    recipient_list = [e[1] for e in settings.HELPDESK + settings.MANAGERS]
147
    try:
148
        send_mail(subject, message, sender, recipient_list,
149
                  connection=get_connection())
150
    except (SMTPException, socket.error) as e:
151
        logger.exception(e)
152
        raise SendNotificationError()
133
    recipient_list = [e[1] for e in settings.HELPDESK +
134
                      settings.MANAGERS + settings.ADMINS]
135
    send_mail(subject, message, sender, recipient_list,
136
              connection=get_connection())
137
    if user:
138
        msg = 'Sent admin notification (%s) for user %s' % (msg,
139
                                                            user.log_display)
153 140
    else:
154
        user = dictionary.get('user')
155
        msg = 'Sent admin notification for user %s' % user.log_display
156
        logger.log(LOGGING_LEVEL, msg)
141
        msg = 'Sent admin notification (%s)' % msg
142

  
143
    logger.log(LOGGING_LEVEL, msg)
157 144

  
158 145

  
159
def send_account_creation_notification(template_name, dictionary=None):
160
    user = dictionary.get('user')
146
def send_account_pending_moderation_notification(
147
        user,
148
        template_name='im/account_pending_moderation_notification.txt'):
149
    """
150
    Notify admins that a new user has verified his email address and moderation
151
    step is required to activate his account.
152
    """
161 153
    subject = _(ACCOUNT_CREATION_SUBJECT) % {'user': user.email}
162
    return _send_admin_notification(template_name, dictionary, subject=subject)
154
    return _send_admin_notification(template_name, {}, subject=subject,
155
                                    user=user, msg="account creation")
163 156

  
164 157

  
165
def send_helpdesk_notification(user, template_name='im/helpdesk_notification.txt'):
158
def send_account_activated_notification(
159
        user,
160
        template_name='im/account_activated_notification.txt'):
166 161
    """
167
    Send email to settings.HELPDESK list to notify for a new user activation.
168

  
169
    Raises SendNotificationError
162
    Send email to settings.HELPDESK + settings.MANAGERES + settings.ADMINS
163
    lists to notify that a new account has been accepted and activated.
170 164
    """
171 165
    message = render_to_string(
172 166
        template_name,
173 167
        {'user': user}
174 168
    )
175 169
    sender = settings.SERVER_EMAIL
176
    recipient_list = [e[1] for e in settings.HELPDESK + settings.MANAGERS]
177
    try:
178
        send_mail(_(HELPDESK_NOTIFICATION_EMAIL_SUBJECT) % {'user': user.email},
179
                  message, sender, recipient_list, connection=get_connection())
180
    except (SMTPException, socket.error) as e:
181
        logger.exception(e)
182
        raise SendNotificationError()
183
    else:
184
        msg = 'Sent helpdesk admin notification for %s' % user.email
185
        logger.log(LOGGING_LEVEL, msg)
170
    recipient_list = [e[1] for e in settings.HELPDESK +
171
                      settings.MANAGERS + settings.ADMINS]
172
    send_mail(_(HELPDESK_NOTIFICATION_EMAIL_SUBJECT) % {'user': user.email},
173
              message, sender, recipient_list, connection=get_connection())
174
    msg = 'Sent helpdesk admin notification for %s' % user.email
175
    logger.log(LOGGING_LEVEL, msg)
186 176

  
187 177

  
188 178
def send_invitation(invitation, template_name='im/invitation.txt'):
189 179
    """
190 180
    Send invitation email.
191

  
192
    Raises SendInvitationError
193 181
    """
194 182
    subject = _(INVITATION_EMAIL_SUBJECT)
195 183
    url = '%s?code=%d' % (join_urls(BASEURL, reverse('index')), invitation.code)
......
200 188
                               'site_name': SITENAME,
201 189
                               'support': CONTACT_EMAIL})
202 190
    sender = settings.SERVER_EMAIL
203
    try:
204
        send_mail(subject, message, sender, [invitation.username],
205
                  connection=get_connection())
206
    except (SMTPException, socket.error) as e:
207
        logger.exception(e)
208
        raise SendInvitationError()
209
    else:
210
        msg = 'Sent invitation %s' % invitation
211
        logger.log(LOGGING_LEVEL, msg)
212
        inviter_invitations = invitation.inviter.invitations
213
        invitation.inviter.invitations = max(0, inviter_invitations - 1)
214
        invitation.inviter.save()
191
    send_mail(subject, message, sender, [invitation.username],
192
              connection=get_connection())
193
    msg = 'Sent invitation %s' % invitation
194
    logger.log(LOGGING_LEVEL, msg)
195
    inviter_invitations = invitation.inviter.invitations
196
    invitation.inviter.invitations = max(0, inviter_invitations - 1)
197
    invitation.inviter.save()
215 198

  
216 199

  
217 200
def send_greeting(user, email_template_name='im/welcome_email.txt'):
218 201
    """
219
    Send welcome email.
202
    Send welcome email to an accepted/activated user.
220 203

  
221 204
    Raises SMTPException, socket.error
222 205
    """
......
228 211
                               'site_name': SITENAME,
229 212
                               'support': CONTACT_EMAIL})
230 213
    sender = settings.SERVER_EMAIL
231
    try:
232
        send_mail(subject, message, sender, [user.email],
233
                  connection=get_connection())
234
    except (SMTPException, socket.error) as e:
235
        logger.exception(e)
236
        raise SendGreetingError()
237
    else:
238
        msg = 'Sent greeting %s' % user.log_display
239
        logger.log(LOGGING_LEVEL, msg)
214
    send_mail(subject, message, sender, [user.email],
215
              connection=get_connection())
216
    msg = 'Sent greeting %s' % user.log_display
217
    logger.log(LOGGING_LEVEL, msg)
240 218

  
241 219

  
242 220
def send_feedback(msg, data, user, email_template_name='im/feedback_mail.txt'):
......
278 256
        logger.log(LOGGING_LEVEL, msg)
279 257

  
280 258

  
281
def activate(
282
    user,
283
    email_template_name='im/welcome_email.txt',
284
    helpdesk_email_template_name='im/helpdesk_notification.txt',
285
    verify_email=False):
286
    """
287
    Activates the specific user and sends email.
288

  
289
    Raises SendGreetingError, ValidationError
290
    """
291
    user.is_active = True
292
    user.email_verified = True
293
    if not user.activation_sent:
294
        user.activation_sent = datetime.now()
295
    user.save()
296
    qh_sync_user(user)
297
    send_helpdesk_notification(user, helpdesk_email_template_name)
298
    send_greeting(user, email_template_name)
299

  
300
def deactivate(user):
301
    user.is_active = False
302
    user.save()
303

  
304 259
def invite(inviter, email, realname):
305 260
    inv = Invitation(inviter=inviter, username=email, realname=realname)
306 261
    inv.save()
......
308 263
    inviter.invitations = max(0, inviter.invitations - 1)
309 264
    inviter.save()
310 265

  
311
def switch_account_to_shibboleth(user, local_user,
312
                                 greeting_template_name='im/welcome_email.txt'):
313
    try:
314
        provider = user.provider
315
    except AttributeError:
316
        return
317
    else:
318
        if not provider == 'shibboleth':
319
            return
320
        user.delete()
321
        local_user.provider = 'shibboleth'
322
        local_user.third_party_identifier = user.third_party_identifier
323
        local_user.save()
324
        send_greeting(local_user, greeting_template_name)
325
        return local_user
326

  
327

  
328
class SendMailError(Exception):
329
    pass
330

  
331

  
332
class SendAdminNotificationError(SendMailError):
333
    def __init__(self):
334
        self.message = _(astakos_messages.ADMIN_NOTIFICATION_SEND_ERR)
335
        super(SendAdminNotificationError, self).__init__()
336

  
337

  
338
class SendVerificationError(SendMailError):
339
    def __init__(self):
340
        self.message = _(astakos_messages.VERIFICATION_SEND_ERR)
341
        super(SendVerificationError, self).__init__()
342

  
343

  
344
class SendInvitationError(SendMailError):
345
    def __init__(self):
346
        self.message = _(astakos_messages.INVITATION_SEND_ERR)
347
        super(SendInvitationError, self).__init__()
348

  
349

  
350
class SendGreetingError(SendMailError):
351
    def __init__(self):
352
        self.message = _(astakos_messages.GREETING_SEND_ERR)
353
        super(SendGreetingError, self).__init__()
354

  
355

  
356
class SendFeedbackError(SendMailError):
357
    def __init__(self):
358
        self.message = _(astakos_messages.FEEDBACK_SEND_ERR)
359
        super(SendFeedbackError, self).__init__()
360

  
361

  
362
class ChangeEmailError(SendMailError):
363
    def __init__(self):
364
        self.message = _(astakos_messages.CHANGE_EMAIL_SEND_ERR)
365
        super(ChangeEmailError, self).__init__()
366

  
367

  
368
class SendNotificationError(SendMailError):
369
    def __init__(self):
370
        self.message = _(astakos_messages.NOTIFICATION_SEND_ERR)
371
        super(SendNotificationError, self).__init__()
372

  
373 266

  
374 267
### PROJECT FUNCTIONS ###
375 268

  
b/snf-astakos-app/astakos/im/management/commands/user-activation-send.py
33 33

  
34 34
from django.core.management.base import BaseCommand, CommandError
35 35

  
36
from astakos.im.functions import send_activation, SendMailError
36
from astakos.im import activation_backends
37
activation_backend = activation_backends.get_backend()
37 38

  
38 39
from ._common import get_user
39 40

  
......
51 52
            if not user:
52 53
                self.stderr.write("Unknown user '%s'\n" % (email_or_id,))
53 54
                continue
54
            if user.email_verified and user.is_active:
55
            if user.email_verified:
55 56
                self.stderr.write(
56
                    "Already active user '%s'\n" % (email_or_id,))
57
                    "User email already verified '%s'\n" % (user.email,))
57 58
                continue
58 59

  
59 60
            try:
60
                send_activation(user)
61
                activation_backend.send_user_verification_email(user)
61 62
            except SendMailError, e:
62 63
                raise CommandError(e.message)
63 64

  
b/snf-astakos-app/astakos/im/management/commands/user-list.py
56 56
        'id': ('id', ('The id of the user')),
57 57
        'real name': ('realname', 'The name of the user'),
58 58
        'active': ('is_active', 'Whether the user is active or not'),
59
        'verified':
60
        ('email_verified', 'Whether the user has a verified email address'),
61
        'moderated':
62
        ('moderated', 'Account moderated'),
59 63
        'admin': ('is_superuser', 'Whether the user is admin or not'),
60 64
        'uuid': ('uuid', 'The uuid of the user'),
61 65
        'providers': (get_providers,
......
66 70
        'groups': (get_groups, 'The groups of the user')
67 71
    }
68 72

  
69
    fields = ['id', 'real name', 'active', 'admin', 'uuid']
73
    fields = ['id', 'real name', 'active', 'verified', 'moderated', 'admin',
74
              'uuid']
70 75

  
71 76
    option_list = ListCommand.option_list + (
72 77
        make_option('-p',
......
94 99
                    dest='active',
95 100
                    default=False,
96 101
                    help="Display only active users"),
102
        make_option('--pending-moderation',
103
                    action='store_true',
104
                    dest='pending_moderation',
105
                    default=False,
106
                    help="Display unmoderated users"),
107
        make_option('--pending-verification',
108
                    action='store_true',
109
                    dest='pending_verification',
110
                    default=False,
111
                    help="Display unverified users"),
97 112
        make_option("--displayname",
98 113
                    dest="displayname",
99 114
                    action="store_true",
......
112 127
        if options['active']:
113 128
            self.filters['is_active'] = True
114 129

  
130
        if options['pending_moderation']:
131
            self.filters['email_verified'] = True
132
            self.filters['moderated'] = False
133

  
134
        if options['pending_verification']:
135
            self.filters['email_verified'] = False
136

  
115 137
        if options['auth_providers']:
116 138
            self.fields.extend(['providers'])
117 139

  
b/snf-astakos-app/astakos/im/management/commands/user-modify.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33 33

  
34
import string
35

  
34 36
from optparse import make_option
35 37

  
36 38
from django.core.management.base import BaseCommand, CommandError
......
38 40
from django.core.exceptions import ValidationError
39 41

  
40 42
from astakos.im.models import AstakosUser
41
from astakos.im.functions import (activate, deactivate)
42 43
from astakos.im import quotas
44
from astakos.im import activation_backends
43 45
from ._common import remove_user_permission, add_user_permission, is_uuid
44 46
from snf_django.lib.db.transaction import commit_on_success_strict
45
import string
47

  
48
activation_backend = activation_backends.get_backend()
46 49

  
47 50

  
48 51
class Command(BaseCommand):
......
92 95
                    dest='inactive',
93 96
                    default=False,
94 97
                    help="Change user's state to inactive"),
98
        make_option('--inactive-reason',
99
                    dest='inactive_reason',
100
                    help="Reason user got inactive"),
95 101
        make_option('--add-group',
96 102
                    dest='add-group',
97 103
                    help="Add user group"),
......
104 110
        make_option('--delete-permission',
105 111
                    dest='delete-permission',
106 112
                    help="Delete user permission"),
113
        make_option('--accept',
114
                    dest='accept',
115
                    action='store_true',
116
                    help="Accept user"),
117
        make_option('--reject',
118
                    dest='reject',
119
                    action='store_true',
120
                    help="Reject user"),
121
        make_option('--reject-reason',
122
                    dest='reject_reason',
123
                    help="Reason user got rejected"),
107 124
        make_option('--set-base-quota',
108 125
                    dest='set_base_quota',
109 126
                    metavar='<resource> <capacity>',
......
140 157
        elif options.get('noadmin'):
141 158
            user.is_superuser = False
142 159

  
160
        if options.get('reject'):
161
            reject_reason = options.get('reject_reason', None)
162
            res = activation_backend.handle_moderation(
163
                user,
164
                accept=False,
165
                reject_reason=reject_reason)
166
            activation_backend.send_result_notifications(res, user)
167
            if res.is_error():
168
                print "Failed to reject.", res.message
169
            else:
170
                print "Account rejected"
171

  
172
        if options.get('accept'):
173
            res = activation_backend.handle_moderation(user, accept=True)
174
            activation_backend.send_result_notifications(res, user)
175
            if res.is_error():
176
                print "Failed to accept.", res.message
177
            else:
178
                print "Account accepted and activated"
179

  
143 180
        if options.get('active'):
144
            activate(user)
181
            res = activation_backend.activate_user(user)
182
            if res.is_error():
183
                print "Failed to activate.", res.message
184
            else:
185
                print "Account %s activated" % user.username
186

  
145 187
        elif options.get('inactive'):
146
            deactivate(user)
188
            res = activation_backend.deactivate_user(
189
                user,
190
                reason=options.get('inactive_reason', None))
191
            if res.is_error():
192
                print "Failed to deactivate,", res.message
193
            else:
194
                print "Account %s deactivated" % user.username
147 195

  
148 196
        invitations = options.get('invitations')
149 197
        if invitations is not None:
b/snf-astakos-app/astakos/im/messages.py
33 33

  
34 34
from django.conf import settings
35 35

  
36
LOGGED_IN_WARNING                       =   'It seems that you are already logged in.'
37
ACCOUNT_ALREADY_VERIFIED                =   'This account is already verified.'
38
ACCOUNT_ALREADY_MODERATED               =   'This account is already moderated.'
36 39
ACCOUNT_ALREADY_ACTIVE                  =   'This account is already active.'
40
ACCOUNT_REJECTED                        =   'This account has been rejected.'
37 41
ACCOUNT_NOT_ACTIVE                      =   'User account is not active.'
42
ACCOUNT_NOT_MODERATED                   =   'User account is not moderated.'
43
ACCOUNT_NOT_VERIFIED                    =   'User account does not have a verified email address.'
38 44
ACCOUNT_RESEND_ACTIVATION               =   'It seems that an activation email has been sent to you, but you have not followed the activation link. <a href="%(send_activation_url)s">Resend activation email.</a>'
39 45
INACTIVE_ACCOUNT_CHANGE_EMAIL           =   ''.join([ACCOUNT_RESEND_ACTIVATION, ' Or <a href="%(signup_url)s">Send activation to a new email.</a>'])
40 46

  
......
42 48

  
43 49
ACCOUNT_ACTIVATED                       =   'Congratulations. Your account has' + \
44 50
                                            ' been activated. You are now logged in.'
51
ACCOUNT_DEACTIVATED                     =   'Your account is inactive'
45 52
PASSWORD_RESET_DONE                     =   'An email with details on how to change your password has been sent. Please check your Inbox.'
46 53
PASSWORD_RESET_CONFIRM_DONE             =   'Your password has changed successfully. You can now login using your new password.'
47 54
PASSWORD_CHANGED                        =   'Your new password was set successfully.'
......
134 141
VERIFICATION_SENT                       =   'Your information has been submitted successfully. A verification email, with an activation link \
135 142
                                               has been sent to the email address you provided. Please follow the activation link on this \
136 143
                                               email to complete the registration process.'
144
VERIFICATION_FAILED                     =   'Email verification process failed.'
137 145
SWITCH_ACCOUNT_LINK_SENT                =   'This email is already associated with a local account, and a verification email has been sent \
138 146
                                             to %(email)s. To complete the association process, go back to your Inbox and follow the link \
139 147
                                             inside the verification email.'
......
235 243
AUTH_PROVIDER_PENDING_RESEND_ACTIVATION      =   '<a href="{resend_activation_url}">Click here to resend activation email.</a>'
236 244
AUTH_PROVIDER_PENDING_MODERATION             =   'Your account request is pending moderation.'
237 245
AUTH_PROVIDER_PENDING_ACTIVATION             =   'Your account request is pending activation.'
238
AUTH_PROVIDER_ACCOUNT_INACTIVE                        =   'Your account is disabled.'
246
AUTH_PROVIDER_ACCOUNT_INACTIVE               =   'Your account is disabled.'
239 247

  
240 248
AUTH_PROVIDER_ADD_TO_EXISTING_ACCOUNT        =   "You can add {method_prompt} to your existing account from your " \
241 249
                                                 " <a href='{profile_url}'>profile page</a>"
/dev/null
1
# encoding: utf-8
2
import datetime
3
from south.db import db
4
from south.v2 import SchemaMigration
5
from django.db import models
6

  
7
class Migration(SchemaMigration):
8

  
9
    def forwards(self, orm):
10
        
11
        # Deleting field 'AstakosUser.provider'
12
        db.delete_column('im_astakosuser', 'provider')
13

  
14
        # Deleting field 'AstakosUser.third_party_identifier'
15
        db.delete_column('im_astakosuser', 'third_party_identifier')
16

  
17

  
18
    def backwards(self, orm):
19
        
20
        # Adding field 'AstakosUser.provider'
21
        db.add_column('im_astakosuser', 'provider', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True), keep_default=False)
22

  
23
        # Adding field 'AstakosUser.third_party_identifier'
24
        db.add_column('im_astakosuser', 'third_party_identifier', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True), keep_default=False)
25

  
26

  
27
    models = {
28
        'auth.group': {
29
            'Meta': {'object_name': 'Group'},
30
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
31
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
32
            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
33
        },
34
        'auth.permission': {
35
            'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
36
            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
37
            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
38
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
39
            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
40
        },
41
        'auth.user': {
42
            'Meta': {'object_name': 'User'},
43
            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
44
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
45
            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
46
            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
47
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
48
            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
49
            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
50
            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
51
            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
52
            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
53
            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
54
            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
55
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff