Example #1
0
def _update_returning_user(
        user_data: user_pb2.User, force_update: bool = False, has_set_email: bool = False) \
        -> timestamp_pb2.Timestamp:
    if user_data.HasField('requested_by_user_at_date'):
        start_of_day = now.get().replace(hour=0,
                                         minute=0,
                                         second=0,
                                         microsecond=0)
        if user_data.requested_by_user_at_date.ToDatetime() >= start_of_day:
            if force_update:
                _save_low_level(user_data)
            return user_data.requested_by_user_at_date
        else:
            last_connection = timestamp_pb2.Timestamp()
            last_connection.CopyFrom(user_data.requested_by_user_at_date)
    else:
        last_connection = user_data.registered_at

    if user_data.profile.email:
        user_data.hashed_email = auth.hash_user_email(user_data.profile.email)

    if has_set_email:
        base_url = parse.urljoin(flask.request.base_url, '/')[:-1]
        advisor.maybe_send_late_activation_emails(
            user_data, flask.current_app.config['DATABASE'], base_url)

    user_data.requested_by_user_at_date.FromDatetime(now.get())
    # No need to pollute our DB with super precise timestamps.
    user_data.requested_by_user_at_date.nanos = 0
    _save_low_level(user_data)

    return last_connection
Example #2
0
    def change_email(self, user_proto: user_pb2.User, auth_request: auth_pb2.AuthRequest) \
            -> user_pb2.User:
        """Change user's email address."""

        new_hashed_email = hash_user_email(auth_request.email)
        if user_proto.hashed_email == new_hashed_email:
            # Trying to set the same email.
            return user_proto

        user_auth_dict = self._user_db.user_auth.find_one(
            {'_id': objectid.ObjectId(user_proto.user_id)})
        if user_auth_dict or auth_request.hashed_password:
            if not user_auth_dict:
                flask.abort(
                    422,
                    i18n.flask_translate(
                        "L'utilisateur n'a pas encore de mot de passe"))
            stored_hashed_password = user_auth_dict.get('hashedPassword', '')
            _check_password(stored_hashed_password, auth_request.hash_salt,
                            auth_request.hashed_password)

        existing = self._user_collection.find_one(
            {'hashedEmail': new_hashed_email}, {'_id': 1})
        if existing:
            flask.abort(
                403,
                i18n.flask_translate(
                    'L\'email "{email}" est déjà utilisé par un autre compte').
                format(email=auth_request.email))

        user_proto.profile.email = auth_request.email
        user_proto.hashed_email = new_hashed_email
        if user_auth_dict:
            self._user_db.user_auth.replace_one(
                {'_id': objectid.ObjectId(user_proto.user_id)},
                {'hashedPassword': auth_request.new_hashed_password})
        self._update_returning_user(user_proto, force_update=True)
        return user_proto
Example #3
0
def save_user(user_data: user_pb2.User,
              is_new_user: bool,
              collection: Optional[pymongo.Collection] = None,
              save_project: _SaveProject = _save_project) -> user_pb2.User:
    """Save a user, updating all the necessary computed fields while doing so."""

    tick.tick('Save user start')

    if is_new_user:
        previous_user_data = user_data
        features.assign_features(user_data.features_enabled, is_new=True)
    else:
        tick.tick('Load old user data')
        previous_user_data = get_user_data(user_data.user_id,
                                           collection=collection)
        if user_data.revision and previous_user_data.revision > user_data.revision:
            # Do not overwrite newer data that was saved already: just return it.
            return previous_user_data
        features.assign_features(previous_user_data.features_enabled,
                                 is_new=False)

    if not previous_user_data.registered_at.seconds:
        common_proto.set_date_now(user_data.registered_at)
        # Disable Advisor for new users in tests.
        if ADVISOR_DISABLED_FOR_TESTING:
            user_data.features_enabled.advisor = features_pb2.CONTROL
            user_data.features_enabled.advisor_email = features_pb2.CONTROL
    elif not _is_test_user(previous_user_data):
        user_data.registered_at.CopyFrom(previous_user_data.registered_at)
        user_data.features_enabled.advisor = previous_user_data.features_enabled.advisor
        user_data.features_enabled.strat_two = previous_user_data.features_enabled.strat_two

    # TODO(pascal): Clean up those multiple populate_feature_flags floating around.
    _populate_feature_flags(user_data)

    for project in user_data.projects:
        previous_project = next((p for p in previous_user_data.projects
                                 if p.project_id == project.project_id),
                                project_pb2.Project())
        save_project(project, previous_project, user_data)

    if user_data.profile.coaching_email_frequency != \
            previous_user_data.profile.coaching_email_frequency:
        # Invalidate the send_coaching_email_after field: it will be recomputed
        # by the focus email script.
        user_data.ClearField('send_coaching_email_after')

    # Update hashed_email field if necessary, to make sure it's consistent with profile.email. This
    # must be done for all users, since (say) a Google authenticated user may try to connect with
    # password, so its email hash must be indexed.
    if user_data.profile.email:
        user_data.hashed_email = auth.hash_user_email(user_data.profile.email)

    if not is_new_user:
        _assert_no_credentials_change(previous_user_data, user_data)
        _copy_unmodifiable_fields(previous_user_data, user_data)
        _populate_feature_flags(user_data)

    user_data.revision += 1

    tick.tick('Save user')
    save_low_level(user_data, is_new_user=is_new_user, collection=collection)
    tick.tick('Return user proto')

    return user_data
Example #4
0
def save_user(user_data: user_pb2.User, is_new_user: bool) \
        -> user_pb2.User:
    """Save a user, updating all the necessary computed fields while doing so."""

    _tick('Save user start')

    if is_new_user:
        previous_user_data = user_data
    else:
        _tick('Load old user data')
        previous_user_data = get_user_data(user_data.user_id)
        if user_data.revision and previous_user_data.revision > user_data.revision:
            # Do not overwrite newer data that was saved already: just return it.
            return previous_user_data

    if not previous_user_data.registered_at.seconds:
        user_data.registered_at.FromDatetime(now.get())
        # No need to pollute our DB with super precise timestamps.
        user_data.registered_at.nanos = 0
        # Disable Advisor for new users in tests.
        if ADVISOR_DISABLED_FOR_TESTING:
            user_data.features_enabled.advisor = user_pb2.CONTROL
            user_data.features_enabled.advisor_email = user_pb2.CONTROL
    elif not _is_test_user(previous_user_data):
        user_data.registered_at.CopyFrom(previous_user_data.registered_at)
        user_data.features_enabled.advisor = previous_user_data.features_enabled.advisor
        user_data.features_enabled.strat_two = previous_user_data.features_enabled.strat_two

    _populate_feature_flags(user_data)

    for project in user_data.projects:
        previous_project = next((p for p in previous_user_data.projects
                                 if p.project_id == project.project_id),
                                project_pb2.Project())
        _save_project(project, previous_project, user_data)

    if user_data.profile.coaching_email_frequency != \
            previous_user_data.profile.coaching_email_frequency:
        # Invalidate the send_coaching_email_after field: it will be recomputed
        # by the focus email script.
        user_data.ClearField('send_coaching_email_after')

    # Update hashed_email field if necessary, to make sure it's consistent with profile.email. This
    # must be done for all users, since (say) a Google authenticated user may try to connect with
    # password, so its email hash must be indexed.
    if user_data.profile.email:
        user_data.hashed_email = auth.hash_user_email(user_data.profile.email)

    if not is_new_user:
        _assert_no_credentials_change(previous_user_data, user_data)
        _copy_unmodifiable_fields(previous_user_data, user_data)
        _populate_feature_flags(user_data)

        if user_data.profile.email and not previous_user_data.profile.email:
            base_url = parse.urljoin(flask.request.base_url, '/')[:-1]
            advisor.maybe_send_late_activation_emails(
                user_data, flask.current_app.config['DATABASE'], base_url)

    user_data.revision += 1

    _tick('Save user')
    _save_low_level(user_data, is_new_user=is_new_user)
    _tick('Return user proto')

    return user_data