Exemple #1
0
    def _handle_duplicate_email_username(self, request, data):
        # pylint: disable=no-member
        # TODO Verify whether this check is needed here - it may be duplicated in user_api.
        email = data.get('email')
        username = data.get('username')
        errors = {}

        # TODO: remove the is_authn_mfe check and use the new error message as default after redesign
        is_authn_mfe = data.get('is_authn_mfe', False)

        error_code = 'duplicate'
        if email is not None and email_exists_or_retired(email):
            error_code += '-email'
            error_message = accounts_settings.AUTHN_EMAIL_CONFLICT_MSG if is_authn_mfe else (
                accounts_settings.EMAIL_CONFLICT_MSG.format(email_address=email)
            )
            errors['email'] = [{'user_message': error_message}]

        if username is not None and username_exists_or_retired(username):
            error_code += '-username'
            error_message = accounts_settings.AUTHN_USERNAME_CONFLICT_MSG if is_authn_mfe else (
                accounts_settings.USERNAME_CONFLICT_MSG.format(username=username)
            )
            errors['username'] = [{'user_message': error_message}]
            errors['username_suggestions'] = generate_username_suggestions(username)

        if errors:
            return self._create_response(request, errors, status_code=409, error_code=error_code)
Exemple #2
0
def _validate_email_change(user, data, field_errors):
    # If user has requested to change email, we must call the multi-step process to handle this.
    # It is not handled by the serializer (which considers email to be read-only).
    if "email" not in data:
        return

    if not settings.FEATURES['ALLOW_EMAIL_ADDRESS_CHANGE']:
        raise AccountUpdateError(
            u"Email address changes have been disabled by the site operators.")

    new_email = data["email"]
    try:
        student_views.validate_new_email(user, new_email)
    except ValueError as err:
        field_errors["email"] = {
            "developer_message":
            u"Error thrown from validate_new_email: '{}'".format(
                text_type(err)),
            "user_message":
            text_type(err)
        }
        return

    # Don't process with sending email to given new email, if it is already associated with
    # an account. User must see same success message with no error.
    # This is so that this endpoint cannot be used to determine if an email is valid or not.
    if email_exists_or_retired(new_email):
        del data["email"]
Exemple #3
0
    def _handle_duplicate_email_username(self, request, data):
        # pylint: disable=no-member
        # TODO Verify whether this check is needed here - it may be duplicated in user_api.
        email = data.get('email')
        username = data.get('username')
        errors = {}

        error_code = 'duplicate'
        if email is not None and email_exists_or_retired(email):
            error_code += '-email'
            errors["email"] = [{
                "user_message":
                accounts_settings.EMAIL_CONFLICT_MSG.format(
                    email_address=email)
            }]

        if username is not None and username_exists_or_retired(username):
            error_code += '-username'
            errors["username"] = [{
                "user_message":
                accounts_settings.USERNAME_CONFLICT_MSG.format(
                    username=username)
            }]

        if errors:
            return self._create_response(request,
                                         errors,
                                         status_code=409,
                                         error_code=error_code)
Exemple #4
0
def _validate_email_doesnt_exist(email):
    """Validate that the email is not associated with an existing user.

    :param email: The proposed email (unicode).
    :return: None
    :raises: errors.AccountEmailAlreadyExists
    """
    if email is not None and email_exists_or_retired(email):
        raise errors.AccountEmailAlreadyExists(_(accounts.EMAIL_CONFLICT_MSG).format(email_address=email))
Exemple #5
0
def check_edxapp_account_conflicts(email, username):
    """
    Exposed function to check conflicts
    """
    conflicts = []

    if username and username_exists_or_retired(username):
        conflicts.append("username")

    if email and email_exists_or_retired(email):
        conflicts.append("email")

    return conflicts
Exemple #6
0
def _validate_email_doesnt_exist(email, api_version='v1'):
    """Validate that the email is not associated with an existing user.

    :param email: The proposed email (unicode).
    :param api_version: Validation API version; it is used to determine the error message
    :return: None
    :raises: errors.AccountEmailAlreadyExists
    """
    if api_version == 'v1':
        error_message = accounts.EMAIL_CONFLICT_MSG.format(email_address=email)
    else:
        error_message = accounts.AUTHN_EMAIL_CONFLICT_MSG

    if email is not None and email_exists_or_retired(email):
        raise errors.AccountEmailAlreadyExists(_(error_message))  # lint-amnesty, pylint: disable=translation-of-non-string
Exemple #7
0
def _validate_secondary_email(user, data, field_errors):
    if "secondary_email" not in data:
        return

    secondary_email = data["secondary_email"]

    try:
        student_views.validate_secondary_email(user, secondary_email)
    except ValueError as err:
        field_errors["secondary_email"] = {
            "developer_message": "Error thrown from validate_secondary_email: '{}'".format(str(err)),
            "user_message": str(err)
        }
    else:
        # Don't process with sending email to given new email, if it is already associated with
        # an account. User must see same success message with no error.
        # This is so that this endpoint cannot be used to determine if an email is valid or not.
        if email_exists_or_retired(secondary_email):
            del data["secondary_email"]
 def clean_email(self):
     """ Enforce email restrictions (if applicable) """
     email = self.cleaned_data["email"]
     if settings.REGISTRATION_EMAIL_PATTERNS_ALLOWED is not None:
         # This Open edX instance has restrictions on what email addresses are allowed.
         allowed_patterns = settings.REGISTRATION_EMAIL_PATTERNS_ALLOWED
         # We append a '$' to the regexs to prevent the common mistake of using a
         # pattern like '.*@edx\\.org' which would match '*****@*****.**'
         if not any(re.match(pattern + "$", email) for pattern in allowed_patterns):
             # This email is not on the whitelist of allowed emails. Check if
             # they may have been manually invited by an instructor and if not,
             # reject the registration.
             if not CourseEnrollmentAllowed.objects.filter(email=email).exists():
                 raise ValidationError(_(u"Unauthorized email address."))
     if email_exists_or_retired(email):
         raise ValidationError(
             _(
                 u"It looks like {email} belongs to an existing account. Try again with a different email address."
             ).format(email=email)
         )
     return email
Exemple #9
0
def do_create_account(form, custom_form=None):
    """
    Given cleaned post variables, create the User and UserProfile objects, as well as the
    registration for this user.

    Returns a tuple (User, UserProfile, Registration).

    Note: this function is also used for creating test users.
    """
    # Check if ALLOW_PUBLIC_ACCOUNT_CREATION flag turned off to restrict user account creation
    if not configuration_helpers.get_value(
            'ALLOW_PUBLIC_ACCOUNT_CREATION',
            settings.FEATURES.get('ALLOW_PUBLIC_ACCOUNT_CREATION', True)):
        raise PermissionDenied()

    errors = {}
    errors.update(form.errors)
    if custom_form:
        errors.update(custom_form.errors)

    if errors:
        raise ValidationError(errors)

    proposed_username = form.cleaned_data["username"]
    user = User(username=proposed_username,
                email=form.cleaned_data["email"],
                is_active=False)
    password = normalize_password(form.cleaned_data["password"])
    user.set_password(password)
    registration = Registration()

    # TODO: Rearrange so that if part of the process fails, the whole process fails.
    # Right now, we can have e.g. no registration e-mail sent out and a zombie account
    try:
        with transaction.atomic():
            user.save()
            if custom_form:
                custom_model = custom_form.save(commit=False)
                custom_model.user = user
                custom_model.save()
    except IntegrityError:
        # Figure out the cause of the integrity error
        # TODO duplicate email is already handled by form.errors above as a ValidationError.
        # The checks for duplicate email/username should occur in the same place with an
        # AccountValidationError and a consistent user message returned (i.e. both should
        # return "It looks like {username} belongs to an existing account. Try again with a
        # different username.")
        if username_exists_or_retired(user.username):
            raise AccountValidationError(
                USERNAME_EXISTS_MSG_FMT.format(username=proposed_username),
                field="username")
        elif email_exists_or_retired(user.email):
            raise AccountValidationError(_(
                "An account with the Email '{email}' already exists.").format(
                    email=user.email),
                                         field="email")
        else:
            raise

    registration.register(user)

    profile_fields = [
        "name", "level_of_education", "gender", "mailing_address", "city",
        "country", "goals", "year_of_birth"
    ]
    profile = UserProfile(
        user=user,
        **{key: form.cleaned_data.get(key)
           for key in profile_fields})
    extended_profile = form.cleaned_extended_profile
    if extended_profile:
        profile.meta = json.dumps(extended_profile)
    try:
        profile.save()
    except Exception:
        log.exception(
            "UserProfile creation failed for user {id}.".format(id=user.id))
        raise

    return user, profile, registration