コード例 #1
0
ファイル: auth.py プロジェクト: cimadure/idealoom
def do_password_change(request):
    token = request.json_body.get('token') or ''
    password = request.json_body.get('password') or ''
    # TODO: Check password quality!
    localizer = request.localizer
    user, validity = verify_password_change_token(token)
    token_date = get_data_token_time(token)
    old_token = (
        user is None or token_date is None or (
            user.last_login and token_date < user.last_login))

    if (validity != Validity.VALID or old_token):
        # V-, V+P+W-B-L-: Invalid or obsolete token (obsolete+logged in treated later.)
        # Offer to send a new token
        if validity != Validity.VALID:
            error = localizer.translate(_(
                "This link is not valid. Do you want us to send another?"))
        else:
            error = localizer.translate(_(
                "This link has been used. Do you want us to send another?"))
        raise JSONError(error, validity)
    user.password_p = password
    user.last_login = datetime.utcnow()
    headers = remember(request, user.id)
    request.response.headerlist.extend(headers)
    return HTTPOk()
コード例 #2
0
ファイル: auth.py プロジェクト: shangxor/assembl
def do_password_change(request):
    token = request.json_body.get('token') or ''
    password1 = request.json_body.get('password1', '').strip()
    password2 = request.json_body.get('password2', '').strip()
    localizer = request.localizer
    if password1 is '' or password2 is '' or password2 != password1:
        error = localizer.translate(
            _("The passwords that were entered are mismatched!"))
        raise JSONError(error, ErrorTypes.PASSWORD)

    # TODO: Check password quality!
    user, validity = verify_password_change_token(token)
    token_date = get_data_token_time(token)
    old_token = (user is None or token_date is None
                 or (user.last_login and token_date < user.last_login))

    if (validity != Validity.VALID or old_token):
        # V-, V+P+W-B-L-: Invalid or obsolete token (obsolete+logged in treated later.)
        # Offer to send a new token
        if validity != Validity.VALID:
            error = localizer.translate(
                _("This link is not valid. Do you want us to send another?"))
        else:
            error = localizer.translate(
                _("This link has been used. Do you want us to send another?"))
        raise JSONError(error, validity)
    user.password_p = password1
    user.successful_login()
    headers = remember(request, user.id)
    request.response.headerlist.extend(headers)
    return HTTPOk()
コード例 #3
0
def finish_password_change(request):
    localizer = request.localizer
    token = request.params.get('token')
    title = request.params.get('title')
    welcome = asbool(request.params.get('welcome'))
    discussion = discussion_from_request(request)
    if welcome:
        title = localizer.translate(
            _('Welcome to {discussion_topic}.')).format(
                discussion_topic=discussion.topic if discussion else "Assembl")
    else:
        title = localizer.translate(_('Change your password'))

    user, validity = verify_password_change_token(token)
    logged_in = request.authenticated_userid  # if mismatch?
    if user and user.id != logged_in:
        # token for someone else: forget login.
        logged_in = None
        forget(request)
    token_date = get_data_token_time(token)
    old_token = (user is None or token_date is None
                 or (user.last_login and token_date < user.last_login))

    if (validity != Validity.VALID or old_token) and not logged_in:
        # V-, V+P+W-B-L-: Invalid or obsolete token (obsolete+logged in treated later.)
        # Offer to send a new token
        if validity != Validity.VALID:
            error = localizer.translate(
                _("This link is not valid. Do you want us to send another?"))
        else:
            error = localizer.translate(
                _("This link has been used. Do you want us to send another?"))
        request.session.flash(error)
        return HTTPFound(location=maybe_contextual_route(
            request,
            'request_password_change',
            _query=dict(user_id=user.id if user else '')))

    error = None
    p1, p2 = (request.params.get('password1', '').strip(),
              request.params.get('password2', '').strip())
    if p1 != p2:
        error = localizer.translate(_('The passwords are not identical'))
    elif p1:
        user.password_p = p1
        user.successful_login()
        headers = remember(request, user.id)
        request.response.headerlist.extend(headers)
        if discussion:
            maybe_auto_subscribe(user, discussion)
        request.session.flash(localizer.translate(_("Password changed")),
                              'message')
        return HTTPFound(location=request.route_url(
            'home' if discussion else 'discussion_list',
            discussion_slug=discussion.slug))

    return dict(get_default_context(request),
                title=title,
                token=token,
                error=error)
コード例 #4
0
ファイル: auth.py プロジェクト: assembl/assembl
def do_password_change(request):
    token = request.json_body.get('token') or ''
    password1 = request.json_body.get('password1', '').strip()
    password2 = request.json_body.get('password2', '').strip()
    localizer = request.localizer
    if password1 is '' or password2 is '' or password2 != password1:
        error = localizer.translate(
            _("The passwords that were entered are mismatched!"))
        raise JSONError(error, ErrorTypes.PASSWORD)

    # TODO: Check password quality!
    user, validity = verify_password_change_token(token)
    token_date = get_data_token_time(token)
    old_token = (
        user is None or token_date is None or (
            user.last_login and token_date < user.last_login))

    if (validity != Validity.VALID or old_token):
        # V-, V+P+W-B-L-: Invalid or obsolete token (obsolete+logged in treated later.)
        # Offer to send a new token
        if validity != Validity.VALID:
            error = localizer.translate(_(
                "This link is not valid. Do you want us to send another?"))
        else:
            error = localizer.translate(_(
                "This link has been used. Do you want us to send another?"))
        raise JSONError(error, validity)
    user.password_p = password1
    user.successful_login()
    headers = remember(request, user.id)
    request.response.headerlist.extend(headers)
    return HTTPOk()
コード例 #5
0
ファイル: views.py プロジェクト: assembl/assembl
def finish_password_change(request):
    localizer = request.localizer
    token = request.params.get('token')
    title = request.params.get('title')
    welcome = asbool(request.params.get('welcome'))
    discussion = discussion_from_request(request)
    if welcome:
        title = localizer.translate(_(
            'Welcome to {discussion_topic}.')).format(
            discussion_topic=discussion.topic if discussion else "Assembl")
    else:
        title = localizer.translate(_('Change your password'))

    user, validity = verify_password_change_token(token)
    logged_in = request.authenticated_userid  # if mismatch?
    if user and user.id != logged_in:
        # token for someone else: forget login.
        logged_in = None
        forget(request)
    token_date = get_data_token_time(token)
    old_token = (
        user is None or token_date is None or (
            user.last_login and token_date < user.last_login))

    if (validity != Validity.VALID or old_token) and not logged_in:
        # V-, V+P+W-B-L-: Invalid or obsolete token (obsolete+logged in treated later.)
        # Offer to send a new token
        if validity != Validity.VALID:
            error = localizer.translate(_(
                "This link is not valid. Do you want us to send another?"))
        else:
            error = localizer.translate(_(
                "This link has been used. Do you want us to send another?"))
        request.session.flash(error)
        return HTTPFound(location=maybe_contextual_route(
            request, 'request_password_change', _query=dict(
                user_id=user.id if user else '')))

    error = None
    p1, p2 = (request.params.get('password1', '').strip(),
              request.params.get('password2', '').strip())
    if p1 != p2:
        error = localizer.translate(_('The passwords are not identical'))
    elif p1:
        user.password_p = p1
        user.successful_login()
        headers = remember(request, user.id)
        request.response.headerlist.extend(headers)
        if discussion:
            maybe_auto_subscribe(user, discussion)
        request.session.flash(localizer.translate(_(
            "Password changed")), 'message')
        return HTTPFound(location=request.route_url(
            'home' if discussion else 'discussion_list',
            discussion_slug=discussion.slug))

    return dict(
        get_default_context(request),
        title=title, token=token, error=error)
コード例 #6
0
ファイル: views.py プロジェクト: festrade/assembl
def finish_password_change(request):
    localizer = request.localizer
    token = request.params.get('token')
    title = request.params.get('title')
    user, validity = verify_password_change_token(token)
    logged_in = authenticated_userid(request)  # if mismatch?
    if user and user.id != logged_in:
        # token for someone else: forget login.
        logged_in = None
        forget(request)
    token_date = get_data_token_time(token)
    old_token = (
        user is None or token_date is None or (
            user.last_login and token_date < user.last_login))

    if (validity != Validity.VALID or old_token) and not logged_in:
        # V-, V+P+W-B-L-: Invalid or obsolete token (obsolete+logged in treated later.)
        # Offer to send a new token
        if validity != Validity.VALID:
            error = localizer.translate(_(
                "This link is not valid. Do you want us to send another?"))
        else:
            error = localizer.translate(_(
                "This link has been used. Do you want us to send another?"))

        return HTTPFound(location=maybe_contextual_route(
            request, 'request_password_change', _query=dict(
                user_id=user.id if user else '',
                error=error)))

    discussion_slug = request.matchdict.get('discussion_slug', None)
    error = None
    p1, p2 = (request.params.get('password1', '').strip(),
              request.params.get('password2', '').strip())
    if p1 != p2:
        error = localizer.translate(_('The passwords are not identical'))
    elif p1:
        user.password_p = p1
        user.last_login = datetime.utcnow()
        headers = remember(request, user.id)
        request.response.headerlist.extend(headers)
        if discussion_slug:
            discussion = discussion_from_request(request)
            maybe_auto_subscribe(user, discussion)
        return HTTPFound(location=request.route_url(
            'home' if discussion_slug else 'discussion_list',
            discussion_slug=discussion_slug,
            _query=dict(
                message=localizer.translate(_(
                    "Password changed")))))

    slug_prefix = "/" + discussion_slug if discussion_slug else ""
    return dict(
        get_default_context(request),
        title=title, slug_prefix=slug_prefix, token=token, error=error)
コード例 #7
0
def finish_password_change(request):
    localizer = request.localizer
    token = request.params.get('token')
    title = request.params.get('title')
    user, validity = verify_password_change_token(token)
    logged_in = authenticated_userid(request)  # if mismatch?
    if user and user.id != logged_in:
        # token for someone else: forget login.
        logged_in = None
        forget(request)
    token_date = get_data_token_time(token)
    old_token = (
        user is None or token_date is None or (
            user.last_login and token_date < user.last_login))

    if (validity != Validity.VALID or old_token) and not logged_in:
        # V-, V+P+W-B-L-: Invalid or obsolete token (obsolete+logged in treated later.)
        # Offer to send a new token
        if validity != Validity.VALID:
            error = localizer.translate(_(
                "This link is not valid. Do you want us to send another?"))
        else:
            error = localizer.translate(_(
                "This link has been used. Do you want us to send another?"))

        return HTTPFound(location=maybe_contextual_route(
            request, 'request_password_change', _query=dict(
                user_id=user.id if user else '',
                error=error)))

    discussion_slug = request.matchdict.get('discussion_slug', None)
    error = None
    p1, p2 = (request.params.get('password1', '').strip(),
              request.params.get('password2', '').strip())
    if p1 != p2:
        error = localizer.translate(_('The passwords are not identical'))
    elif p1:
        user.password_p = p1
        user.last_login = datetime.utcnow()
        headers = remember(request, user.id)
        request.response.headerlist.extend(headers)
        if discussion_slug:
            discussion = discussion_from_request(request)
            maybe_auto_subscribe(user, discussion)
        return HTTPFound(location=request.route_url(
            'home' if discussion_slug else 'discussion_list',
            discussion_slug=discussion_slug,
            _query=dict(
                message=localizer.translate(_(
                    "Password changed")))))

    slug_prefix = "/" + discussion_slug if discussion_slug else ""
    return dict(
        get_default_context(request),
        title=title, slug_prefix=slug_prefix, token=token, error=error)
コード例 #8
0
def do_password_change(request):
    "Validate the change_password token, and react accordingly."
    # Codes below refer to those cases:
    # V. token Valid(+) or invalid(-)? (Possibly expired through internal date)
    # P. user has(+) a Password or not (-)?
    # W. Welcome(+) vs change password(-)
    # B. last login absent, or Before token created (+) vs last login after token created (-)
    # L. user is already Logged in(+) or not(-)?

    welcome = 'welcome' in request.matched_route.name
    localizer = request.localizer
    discussion = discussion_from_request(request)
    token = request.matchdict.get('token')
    user, validity = verify_password_change_token(token)
    logged_in = authenticated_userid(request)
    if user and user.id != logged_in:
        # token for someone else: forget login.
        logged_in = None
        forget(request)
    lacking_password = user is not None and user.password is None
    token_date = get_data_token_time(token)
    old_token = (
        user is None or token_date is None or (
            user.last_login and token_date < user.last_login))
    print "pwc V%sP%sW%sB%sL%s" % tuple(map(lambda b: "-" if b else "+", (
        validity != Validity.VALID, lacking_password, not welcome,
        old_token, logged_in is None)))
    if welcome and not lacking_password:
        # W+P+: welcome link sends onwards irrespective of token
        if logged_in:
            # L+: send onwards to discussion
            return HTTPFound(location=request.route_url(
                'home' if discussion else 'discussion_list',
                discussion_slug=discussion.slug))
        else:
            # L-: offer to login
            return HTTPFound(location=maybe_contextual_route(
                request, 'login', _query=dict(
                identifier=user.get_preferred_email() if user else None)))

    if (validity != Validity.VALID or old_token) and not logged_in:
        # V-, V+P+W-B-L-: Invalid or obsolete token (obsolete+logged in treated later.)
        # Offer to send a new token
        if validity != Validity.VALID:
            error = localizer.translate(_(
                "This link is not valid. Do you want us to send another?"))
        else:
            error = localizer.translate(_(
                "This link has been used. Do you want us to send another?"))
        request.session.flash(error)
        return HTTPFound(location=maybe_contextual_route(
            request, 'request_password_change', _query=dict(
                user_id=user.id if user else '')))

    # V+: Valid token (encompasses P-B+, W-, B-L+); ALSO V-L+
    # V+P-B- should not happen, but we'll treat it the same.
    # go through password change dialog. We'll complete login afterwards.
    if welcome:
        if discussion:
            request.session.flash(localizer.translate(_(
                "You will enter the discussion as <b>{name}</b>.")
                ).format(name=user.name), 'message')
        else:
            request.session.flash(localizer.translate(_(
                "You will enter Assembl as <b>{name}</b>.")
                ).format(name=user.name), 'message')
        request.session.flash(localizer.translate(_(
                "Please choose your password for security reasons.")
                ).format(name=user.name), 'message')
    return HTTPFound(location=maybe_contextual_route(
            request, 'react_do_password_change', _query=dict(
                token=token, welcome=welcome)))
コード例 #9
0
def user_confirm_email(request):
    token = request.matchdict.get('token') or ''
    account, validity = verify_email_token(token)
    session = AbstractAgentAccount.default_db
    logged_in = authenticated_userid(request)  # if mismatch?
    localizer = request.localizer
    if account and account.profile_id != logged_in:
        # token for someone else: forget login.
        logged_in = None
        forget(request)
    token_date = get_data_token_time(token)
    old_token = (
        account is None or token_date is None or (
            account.profile.last_login and token_date < account.profile.last_login))
    inferred_discussion = discussion = discussion_from_request(request)
    if account and not discussion:
        # We do not know from which discussion the user started to log in;
        # See if only involved in one discussion
        discussions = account.profile.involved_in_discussion
        if len(discussions) == 1:
            inferred_discussion = discussions[0]
    if account and account.verified and logged_in:
        # no need to revalidate, just send to discussion.
        # Question: maybe_auto_subscribe? Doubt it.
        if inferred_discussion:
            if inferred_discussion.preferences['landing_page']:
                route = 'new_home'
            else:
                route = 'home'
        else:
            route = 'discussion_list'
        error = localizer.translate(
            _("Email <%s> already confirmed")) % (account.email,)
        request.session.flash(error)
        return HTTPFound(location=request.route_url(
            route,
            discussion_slug=inferred_discussion.slug if inferred_discussion else None))

    if validity != Validity.VALID or old_token:
        # V-, B-: Invalid or obsolete token
        # Offer to send a new token
        if account and not account.verified:
            # bad token, unverified account... offer a new token
            if validity != Validity.VALID:
                error = localizer.translate(_(
                    "This link was not valid. We sent another."))
            else:
                error = localizer.translate(_(
                    "This link has been used. We sent another."))
            request.session.flash(error)
            return HTTPFound(location=maybe_contextual_route(
                request, 'confirm_emailid_sent', email_account_id=account.id))
        else:
            if account and account.verified:
                # bad token, verified account... send them to login
                error = localizer.translate(
                    _("Email <%s> already confirmed")) % (account.email,)
            else:
                # now what? We do not have the email.
                # Just send to login for now
                error = localizer.translate(_(
                    "This link is not valid. Please attempt to login to get another one."))
            request.session.flash(error)
            return HTTPFound(location=maybe_contextual_route(
                request, 'react_login', _query=dict(
                    identifier=account.email if account else None)))

    # By now we know we have a good token; make it login-equivalent.
    user = account.profile
    assert isinstance(user, User)  # accounts should not get here. OK to fail.
    headers = remember(request, user.id)
    request.response.headerlist.extend(headers)
    user.last_login = datetime.utcnow()
    username = user.username.username if user.username else None
    next_view = handle_next_view(request, False)

    if account.verified:
        message = localizer.translate(
            _("Email <%s> already confirmed")) % (account.email,)
    else:
        # maybe another profile already verified that email
        other_account = session.query(AbstractAgentAccount).filter_by(
            email_ci=account.email_ci, verified=True).first()
        if other_account:
            # We have two versions of the email, delete the unverified one
            session.delete(account)
            if other_account.profile != user:
                # Give priority to the one where the email was verified last.
                other_profile = other_account.profile
                user.merge(other_profile)
                session.delete(other_profile)
                if user.username:
                    username = user.username.username
            account = other_account
        account.verified = True
        user.verified = True
        # do not use inferred discussion for auto_subscribe
        user.last_login = datetime.utcnow()
        if discussion and maybe_auto_subscribe(user, discussion):
            message = localizer.translate(_(
                "Your email address %s has been confirmed, "
                "and you are now subscribed to discussion's "
                "default notifications.")) % (account.email,)
        else:
            message = localizer.translate(_(
                "Your email address %s has been confirmed."
                )) % (account.email,)

    if inferred_discussion:
        if inferred_discussion.preferences['landing_page']:
            route = 'new_home'
        else:
            route = 'home'
    else:
        route = 'discussion_list'
    return HTTPFound(location=request.route_url(
        route,
        discussion_slug=inferred_discussion.slug
        if inferred_discussion else None,
        _query=dict(message=message)))
コード例 #10
0
ファイル: views.py プロジェクト: festrade/assembl
def do_password_change(request):
    "Validate the change_password token, and react accordingly."
    # Codes below refer to those cases:
    # V. token Valid(+) or invalid(-)? (Possibly expired through internal date)
    # P. user has(+) a Password or not (-)?
    # W. Welcome(+) vs change password(-)
    # B. last login absent, or Before token created (+) vs last login after token created (-)
    # L. user is already Logged in(+) or not(-)?

    welcome = 'welcome' in request.matched_route.name
    localizer = request.localizer
    discussion = discussion_from_request(request)
    token = request.matchdict.get('ticket')
    user, validity = verify_password_change_token(token)
    logged_in = authenticated_userid(request)
    if user and user.id != logged_in:
        # token for someone else: forget login.
        logged_in = None
        forget(request)
    lacking_password = user is not None and user.password is None
    token_date = get_data_token_time(token)
    old_token = (
        user is None or token_date is None or (
            user.last_login and token_date < user.last_login))
    print "pwc V%sP%sW%sB%sL%s" % tuple(map(lambda b: "-" if b else "+", (
        validity != Validity.VALID, lacking_password, not welcome,
        old_token, logged_in is None)))
    if welcome and not lacking_password:
        # W+P+: welcome link sends onwards irrespective of token
        if logged_in:
            # L+: send onwards to discussion
            return HTTPFound(location=request.route_url(
                'home' if discussion else 'discussion_list',
                discussion_slug=discussion.slug))
        else:
            # L-: offer to login
            return HTTPFound(location=maybe_contextual_route(
                request, 'login', _query=dict(
                identifier=user.get_preferred_email() if user else None)))

    if (validity != Validity.VALID or old_token) and not logged_in:
        # V-, V+P+W-B-L-: Invalid or obsolete token (obsolete+logged in treated later.)
        # Offer to send a new token
        if validity != Validity.VALID:
            error = localizer.translate(_(
                "This link is not valid. Do you want us to send another?"))
        else:
            error = localizer.translate(_(
                "This link has been used. Do you want us to send another?"))

        return HTTPFound(location=maybe_contextual_route(
            request, 'request_password_change', _query=dict(
                user_id=user.id if user else '',
                error=error)))

    # V+: Valid token (encompasses P-B+, W-, B-L+); ALSO V-L+
    # V+P-B- should not happen, but we'll treat it the same.
    # go through password change dialog. We'll complete login afterwards.
    slug = discussion.slug if discussion else ""
    slug_prefix = "/" + slug if slug else ""
    if welcome:
        if discussion:
            discussion_topic = discussion.topic
            welcome_text = localizer.translate(_(
                "You will enter the discussion as <b>{name}</b>.")).format(name=user.name)
        else:
            discussion_topic = "Assembl"
            welcome_text = localizer.translate(_(
                "You will enter Assembl as <b>{name}</b>."))
        welcome_text += "</p><p>" + localizer.translate(_(
            "Please choose your password for security reasons."))
        title = localizer.translate(_('Welcome to {discussion_topic}.')).format(
            discussion_topic=discussion_topic)
    else:
        title = localizer.translate(_('Change your password'))
        welcome_text = ""
    return dict(
        get_default_context(request),
        slug_prefix=slug_prefix,
        description=welcome_text,
        token=token,
        title=title)
コード例 #11
0
ファイル: views.py プロジェクト: festrade/assembl
def user_confirm_email(request):
    token = request.matchdict.get('ticket')
    account, validity = verify_email_token(token)
    session = AbstractAgentAccount.default_db
    logged_in = authenticated_userid(request)  # if mismatch?
    localizer = request.localizer
    if account and account.profile_id != logged_in:
        # token for someone else: forget login.
        logged_in = None
        forget(request)
    token_date = get_data_token_time(token)
    old_token = (
        account is None or token_date is None or (
            account.profile.last_login and token_date < account.profile.last_login))
    inferred_discussion = discussion = discussion_from_request(request)
    if account and not discussion:
        # We do not know from which discussion the user started to log in;
        # See if only involved in one discussion
        discussions = account.profile.involved_in_discussion
        if len(discussions) == 1:
            inferred_discussion = discussions[0]
    if account.verified and logged_in:
        # no need to revalidate, just send to discussion.
        # Question: maybe_auto_subscribe? Doubt it.
        return HTTPFound(location=request.route_url(
            'home' if inferred_discussion else 'discussion_list',
            discussion_slug=inferred_discussion.slug,
            _query=dict(message=localizer.translate(
                _("Email <%s> already confirmed")) % (account.email,))))

    if validity != Validity.VALID or old_token:
        # V-, B-: Invalid or obsolete token
        # Offer to send a new token
        if account and not account.verified:
            # bad token, unverified account... offer a new token
            if validity != Validity.VALID:
                error = localizer.translate(_(
                    "This link was not valid. We sent another."))
            else:
                error = localizer.translate(_(
                    "This link has been used. We sent another."))
            return HTTPFound(location=maybe_contextual_route(
                request, 'confirm_emailid_sent', email_account_id=account.id,
                _query=(dict(error=error))))
        else:
            if account and account.verified:
                # bad token, verified account... send them to login
                error = localizer.translate(
                    _("Email <%s> already confirmed")) % (account.email,)
            else:
                # now what? We do not have the email.
                # Just send to login for now
                error = localizer.translate(_(
                    "This link is not valid. Please attempt to login to get another one."
                    )) % (account.email,)
            return HTTPFound(location=maybe_contextual_route(
                request, 'login', _query=dict(
                    identifier=account.email if account else None,
                    message=error)))

    # By now we know we have a good token; make it login-equivalent.
    user = account.profile
    assert isinstance(user, User)  # accounts should not get here. OK to fail.
    headers = remember(request, user.id)
    request.response.headerlist.extend(headers)
    user.last_login = datetime.utcnow()
    username = user.username.username if user.username else None
    next_view = handle_next_view(request, False)

    if account.verified:
        message = localizer.translate(
            _("Email <%s> already confirmed")) % (account.email,)
    else:
        # maybe another profile already verified that email
        other_account = session.query(AbstractAgentAccount).filter_by(
            email_ci=account.email_ci, verified=True).first()
        if other_account:
            # We have two versions of the email, delete the unverified one
            session.delete(account)
            if other_account.profile != user:
                # Give priority to the one where the email was verified last.
                other_profile = other_account.profile
                user.merge(other_profile)
                session.delete(other_profile)
                if user.username:
                    username = user.username.username
            account = other_account
        account.verified = True
        user.verified = True
        # do not use inferred discussion for auto_subscribe
        user.last_login = datetime.utcnow()
        if discussion and maybe_auto_subscribe(user, discussion):
            message = localizer.translate(_(
                "Your email address %s has been confirmed, "
                "and you are now subscribed to discussion's "
                "default notifications.")) % (account.email,)
        else:
            message = localizer.translate(_(
                "Your email address %s has been confirmed."
                )) % (account.email,)

    if inferred_discussion:
        return HTTPFound(location=request.route_url(
            'home', discussion_slug=inferred_discussion.slug,
            _query=dict(message=message)))
    else:
        return HTTPFound(
            location=request.route_url('discussion_list'))