def upload_welcome_pdf(dropbox_id):
    user = User.query.filter_by(dropbox_id=dropbox_id,
                                active=True).first()
    if user is None:
        return False

    # If we've already sent the welcome PDF before, Dropbox webhook went
    # trigger, so do it here.
    if user.uploaded_welcome_pdf:
        return kindlebox(dropbox_id)

    analytics.track(str(user.id), 'Sent welcome pdf')

    client = DropboxClient(user.access_token)
    try:
        with open('app/static/bookdrop_welcome.pdf', 'rb') as f:
            response = client.put_file('Welcome to BookDrop.pdf', f, overwrite=True)
            if response:
                log.info(u"Welcome PDF sent to user ID {0}.".format(user.id))
            else:
                raise Exception("No response received after sending welcome PDF")

        user.set_uploaded_welcome_pdf()
        db.session.commit()

    except:
        log.error((u"Welcome PDF failed for user ID "
                   "{0}.").format(user.id), exc_info=True)
        return False

    return True
Beispiel #2
0
def deactivate(user):
    if user.active:
        user.kindle_names.delete()
    user.set_active(False)
    db.session.commit()

    analytics.track(str(user.id), 'Deactivated account')

    return jsonify({
            'success': True,
            })
Beispiel #3
0
def activate():
    dropbox_id = session.get('dropbox_id')
    if dropbox_id is None:
        log.warn("Error activating, user with dropbox id {0} wasn't logged "
                 "in".format(dropbox_id))
        abort(400)

    user = User.query.filter_by(dropbox_id=dropbox_id).first()
    if user is None:
        log.warn("Error activating, user with dropbox id {0} doesn't "
                 "exist".format(dropbox_id))
        abort(400)

    if not user.active:
        if 'kindle_names' not in request.form:
            log.warn("Error activating, user with dropbox id {0} submitted "
                     "no kindle names".format(dropbox_id))
            abort(400)

        # Add all the Kindle usernames.
        form_kindle_names = request.form.get('kindle_names')
        try:
            kindle_names = json.loads(form_kindle_names)
        except json.JSONDecodeError:
            log.warn("Error activating, user with dropbox id {dropbox_id} "
                     "submitted invalid kindle names "
                     "{kindle_names}".format(dropbox_id=dropbox_id,
                                             kindle_names=form_kindle_names))
            abort(400)

        if type(kindle_names) != list:
            log.warn("Error activating, user with dropbox id {dropbox_id} did "
                     "not submit list of kindle names "
                     "{kindle_names}".format(dropbox_id=dropbox_id,
                                             kindle_names=kindle_names))
            abort(400)

        log.info("User with dropbox id {dropbox_id} submitting list of kindle "
                 "names {kindle_names}".format(dropbox_id=dropbox_id,
                                               kindle_names=kindle_names))

        for kindle_name in kindle_names:
            kindle_name = validate_kindle_name(kindle_name)
            if kindle_name is None:
                continue
            kindle_name_row = KindleName(user.id, kindle_name)
            db.session.add(kindle_name_row)

        db.session.flush()
        # TODO: Return an error to the client
        if user.kindle_names.first() is None:
            log.warn("Error activating, user with dropbox id {0} submitted "
                     "invalid kindle names".format(dropbox_id))
            abort(400)

        user.set_active(True)
        db.session.commit()

        try:
            upload_welcome_pdf.delay(user.dropbox_id)
        except:
            log.error("Unable to add upload welcome PDF task for dropbox id "
                      "{0}".format(user.dropbox_id), exc_info=True)
            pass

        analytics.track(str(user.id), 'Activated account')

    return redirect(url_for('home'))
Beispiel #4
0
    if dropbox_id is None:
        return redirect(url_for('home'))

    user = User.query.filter_by(dropbox_id=dropbox_id).first()
    new_user = user is None
    if user is None:
        user = User(dropbox_id)
        user.set_new_emailer()
        db.session.add(user)

    user.access_token = access_token
    (user.name, user.email) = get_dropbox_name_email(access_token)
    db.session.commit()

    if new_user:
        analytics.track(str(user.id), 'Registered')
    analytics.track(str(user.id), 'Logged in')

    session['dropbox_id'] = user.dropbox_id

    return redirect(url_for('home'))


@app.route('/dropbox-unlink')
def dropbox_unlink():
    dropbox_id = session.get('dropbox_id')
    if dropbox_id is None:
        abort(403)

    user = User.query.filter_by(dropbox_id=dropbox_id).first()
    for attribute in ['active', 'access_token', 'cursor']:
Beispiel #5
0
    if dropbox_id is None:
        return redirect(url_for('home'))

    user = User.query.filter_by(dropbox_id=dropbox_id).first()
    new_user = user is None
    if user is None:
        user = User(dropbox_id)
        user.set_new_emailer()
        db.session.add(user)

    user.access_token = access_token
    (user.name, user.email) = get_dropbox_name_email(access_token)
    db.session.commit()

    if new_user:
        analytics.track(str(user.id), 'Registered')
    analytics.track(str(user.id), 'Logged in')

    session['dropbox_id'] = user.dropbox_id

    return redirect(url_for('home'))


@app.route('/dropbox-unlink')
def dropbox_unlink():
    dropbox_id = session.get('dropbox_id')
    if dropbox_id is None:
        abort(403)

    user = User.query.filter_by(dropbox_id=dropbox_id).first()
    for attribute in ['active', 'access_token', 'cursor']:
Beispiel #6
0
def _conduct_oauth_login(auth_system,
                         login_service,
                         lid,
                         lusername,
                         lemail,
                         metadata=None,
                         captcha_verified=False):
    """
    Conducts login from the result of an OAuth service's login flow and returns the status of the
    login, as well as the followup step.
    """
    service_id = login_service.service_id()
    service_name = login_service.service_name()

    # Check for an existing account *bound to this service*. If found, conduct login of that account
    # and redirect.
    user_obj = model.user.verify_federated_login(service_id, lid)
    if user_obj is not None:
        return _oauthresult(user_obj=user_obj, service_name=service_name)

    # If the login service has a bound field name, and we have a defined internal auth type that is
    # not the database, then search for an existing account with that matching field. This allows
    # users to setup SSO while also being backed by something like LDAP.
    bound_field_name = login_service.login_binding_field()
    if auth_system.federated_service is not None and bound_field_name is not None:
        # Perform lookup.
        logger.debug('Got oauth bind field name of "%s"', bound_field_name)
        lookup_value = None
        if bound_field_name == "sub":
            lookup_value = lid
        elif bound_field_name == "username":
            lookup_value = lusername
        elif bound_field_name == "email":
            lookup_value = lemail

        if lookup_value is None:
            logger.error("Missing lookup value for OAuth login")
            return _oauthresult(
                service_name=service_name,
                error_message="Configuration error in this provider")

        (user_obj, err) = auth_system.link_user(lookup_value)
        if err is not None:
            logger.debug("%s %s not found: %s", bound_field_name, lookup_value,
                         err)
            msg = "%s %s not found in backing auth system" % (bound_field_name,
                                                              lookup_value)
            return _oauthresult(service_name=service_name, error_message=msg)

        # Found an existing user. Bind their internal auth account to this service as well.
        result = _attach_service(login_service, user_obj, lid, lusername)
        if result.error_message is not None:
            return result

        return _oauthresult(user_obj=user_obj, service_name=service_name)

    # Otherwise, we need to create a new user account.
    blacklisted_domains = app.config.get("BLACKLISTED_EMAIL_DOMAINS", [])
    if not can_create_user(lemail, blacklisted_domains=blacklisted_domains):
        error_message = "User creation is disabled. Please contact your administrator"
        return _oauthresult(service_name=service_name,
                            error_message=error_message)

    if features.RECAPTCHA and not captcha_verified:
        return _oauthresult(service_name=service_name,
                            requires_verification=True)

    # Try to create the user
    try:
        # Generate a valid username.
        new_username = None
        for valid in generate_valid_usernames(lusername):
            if model.user.get_user_or_org(valid):
                continue

            new_username = valid
            break

        requires_password = auth_system.requires_distinct_cli_password
        prompts = model.user.get_default_user_prompts(features)
        user_obj = model.user.create_federated_user(
            new_username,
            lemail,
            service_id,
            lid,
            set_password_notification=requires_password,
            metadata=metadata or {},
            confirm_username=features.USERNAME_CONFIRMATION,
            prompts=prompts,
            email_required=features.MAILING,
        )

        # Success, tell analytics
        analytics.track(user_obj.username, "register",
                        {"service": service_name.lower()})
        return _oauthresult(user_obj=user_obj, service_name=service_name)

    except model.InvalidEmailAddressException:
        message = ("The e-mail address {0} is already associated "
                   "with an existing {1} account. \n"
                   "Please log in with your username and password and "
                   "associate your {2} account to use it in the future.")
        message = message.format(lemail, app.config["REGISTRY_TITLE_SHORT"],
                                 service_name)
        return _oauthresult(service_name=service_name,
                            error_message=message,
                            register_redirect=True)

    except model.DataModelException as ex:
        return _oauthresult(service_name=service_name, error_message=str(ex))