Ejemplo n.º 1
0
def mfa_setup():
    if current_user.enable_otp:
        flash("you have already enabled MFA", "warning")
        return redirect(url_for("dashboard.index"))

    otp_token_form = OtpTokenForm()

    if not current_user.otp_secret:
        LOG.d("Generate otp_secret for user %s", current_user)
        current_user.otp_secret = pyotp.random_base32()
        Session.commit()

    totp = pyotp.TOTP(current_user.otp_secret)

    if otp_token_form.validate_on_submit():
        token = otp_token_form.token.data.replace(" ", "")

        if totp.verify(token) and current_user.last_otp != token:
            current_user.enable_otp = True
            current_user.last_otp = token
            Session.commit()
            flash("MFA has been activated", "success")

            return redirect(url_for("dashboard.recovery_code_route"))
        else:
            flash("Incorrect token", "warning")

    otp_uri = pyotp.totp.TOTP(current_user.otp_secret).provisioning_uri(
        name=current_user.email, issuer_name="SimpleLogin")

    return render_template("dashboard/mfa_setup.html",
                           otp_token_form=otp_token_form,
                           otp_uri=otp_uri)
Ejemplo n.º 2
0
def test_should_disable_bounces_every_day(flask_client):
    """if an alias has bounces every day at least 9 days in the last 10 days, disable alias"""
    user = login(flask_client)
    alias = Alias.create_new_random(user)
    Session.commit()

    assert not should_disable(alias)

    # create a lot of bounce on this alias
    contact = Contact.create(
        user_id=user.id,
        alias_id=alias.id,
        website_email="*****@*****.**",
        reply_email="*****@*****.**",
        commit=True,
    )
    for i in range(9):
        EmailLog.create(
            user_id=user.id,
            contact_id=contact.id,
            alias_id=contact.alias_id,
            commit=True,
            bounced=True,
            created_at=arrow.now().shift(days=-i),
        )

    assert should_disable(alias)
Ejemplo n.º 3
0
def test_should_disable_bounce_consecutive_days(flask_client):
    user = login(flask_client)
    alias = Alias.create_new_random(user)
    Session.commit()

    contact = Contact.create(
        user_id=user.id,
        alias_id=alias.id,
        website_email="*****@*****.**",
        reply_email="*****@*****.**",
        commit=True,
    )

    # create 6 bounce on this alias in the last 24h: alias is not disabled
    for _ in range(6):
        EmailLog.create(
            user_id=user.id,
            contact_id=contact.id,
            alias_id=contact.alias_id,
            commit=True,
            bounced=True,
        )
    assert not should_disable(alias)

    # create 2 bounces in the last 7 days: alias should be disabled
    for _ in range(2):
        EmailLog.create(
            user_id=user.id,
            contact_id=contact.id,
            alias_id=contact.alias_id,
            commit=True,
            bounced=True,
            created_at=arrow.now().shift(days=-3),
        )
    assert should_disable(alias)
Ejemplo n.º 4
0
def test_import_no_mailboxes(flask_client):
    # Create user
    user = login(flask_client)

    # Check start state
    assert len(Alias.filter_by(user_id=user.id).all()) == 1  # Onboarding alias

    # Create domain
    CustomDomain.create(
        user_id=user.id, domain="my-domain.com", ownership_verified=True
    )
    Session.commit()

    alias_data = [
        "alias,note",
        "[email protected],Used on eBay",
        '[email protected],"Used on Facebook, Instagram."',
    ]

    file = File.create(path="/test", commit=True)
    batch_import = BatchImport.create(user_id=user.id, file_id=file.id)

    import_from_csv(batch_import, user, alias_data)

    assert len(Alias.filter_by(user_id=user.id).all()) == 3  # +2
Ejemplo n.º 5
0
def test_alias_transfer(flask_client):
    user = login(flask_client)
    mb = Mailbox.create(user_id=user.id, email="*****@*****.**", commit=True)

    alias = Alias.create_new_random(user)
    Session.commit()

    AliasMailbox.create(alias_id=alias.id, mailbox_id=mb.id, commit=True)

    new_user = User.create(
        email="*****@*****.**",
        password="******",
        activated=True,
        commit=True,
    )

    Mailbox.create(
        user_id=new_user.id, email="*****@*****.**", verified=True, commit=True
    )

    alias_transfer.transfer(alias, new_user, new_user.mailboxes())

    # refresh from db
    alias = Alias.get(alias.id)
    assert alias.user == new_user
    assert set(alias.mailboxes) == set(new_user.mailboxes())
    assert len(alias.mailboxes) == 2
Ejemplo n.º 6
0
def setup_sl_domain() -> SLDomain:
    """Take the first SLDomain and set its can_use_subdomain=True"""
    sl_domain: SLDomain = SLDomain.first()
    sl_domain.can_use_subdomain = True
    Session.commit()

    return sl_domain
Ejemplo n.º 7
0
def test_create_delete_api_key(flask_client):
    user = login(flask_client)
    Session.commit()

    # create api_key
    create_r = flask_client.post(
        url_for("dashboard.api_key"),
        data={
            "form-name": "create",
            "name": "for test"
        },
        follow_redirects=True,
    )
    assert create_r.status_code == 200
    api_key = ApiKey.get_by(user_id=user.id)
    assert ApiKey.count() == 1
    assert api_key.name == "for test"

    # delete api_key
    delete_r = flask_client.post(
        url_for("dashboard.api_key"),
        data={
            "form-name": "delete",
            "api-key-id": api_key.id
        },
        follow_redirects=True,
    )
    assert delete_r.status_code == 200
    assert ApiKey.count() == 0
Ejemplo n.º 8
0
def delete_alias(alias: Alias, user: User):
    """
    Delete an alias and add it to either global or domain trash
    Should be used instead of Alias.delete, DomainDeletedAlias.create, DeletedAlias.create
    """
    # save deleted alias to either global or domain trash
    if alias.custom_domain_id:
        if not DomainDeletedAlias.get_by(email=alias.email,
                                         domain_id=alias.custom_domain_id):
            LOG.d("add %s to domain %s trash", alias, alias.custom_domain_id)
            Session.add(
                DomainDeletedAlias(
                    user_id=user.id,
                    email=alias.email,
                    domain_id=alias.custom_domain_id,
                ))
            Session.commit()

    else:
        if not DeletedAlias.get_by(email=alias.email):
            LOG.d("add %s to global trash", alias)
            Session.add(DeletedAlias(email=alias.email))
            Session.commit()

    LOG.i("delete alias %s", alias)
    Alias.filter(Alias.id == alias.id).delete()
    Session.commit()
Ejemplo n.º 9
0
def test_auth_login_success(flask_client, mfa: bool):
    User.create(
        email="*****@*****.**",
        password=PASSWORD_1,
        name="Test User",
        activated=True,
        enable_otp=mfa,
    )
    Session.commit()

    r = flask_client.post(
        "/api/auth/login",
        json={
            "email": "*****@*****.**",
            "password": PASSWORD_2,
            "device": "Test Device",
        },
    )

    assert r.status_code == 200
    assert r.json["name"] == "Test User"
    assert r.json["email"]

    if mfa:
        assert r.json["api_key"] is None
        assert r.json["mfa_enabled"]
        assert r.json["mfa_key"]
    else:
        assert r.json["api_key"]
        assert not r.json["mfa_enabled"]
        assert r.json["mfa_key"] is None
Ejemplo n.º 10
0
def test_cancel_mailbox_email_change(flask_client):
    user = login(flask_client)

    # create a mailbox
    mb = Mailbox.create(user_id=user.id, email="*****@*****.**")
    Session.commit()

    # update mailbox email
    r = flask_client.put(
        f"/api/mailboxes/{mb.id}",
        json={"email": "*****@*****.**"},
    )
    assert r.status_code == 200

    mb = Mailbox.get(mb.id)
    assert mb.new_email == "*****@*****.**"

    # cancel mailbox email change
    r = flask_client.put(
        url_for("api.delete_mailbox", mailbox_id=mb.id),
        json={"cancel_email_change": True},
    )
    assert r.status_code == 200

    mb = Mailbox.get(mb.id)
    assert mb.new_email is None
Ejemplo n.º 11
0
def test_set_mailbox_as_default(flask_client):
    user = login(flask_client)

    mb = Mailbox.create(user_id=user.id,
                        email="*****@*****.**",
                        verified=True,
                        commit=True)
    assert user.default_mailbox_id != mb.id

    r = flask_client.put(
        f"/api/mailboxes/{mb.id}",
        json={"default": True},
    )

    assert r.status_code == 200
    assert user.default_mailbox_id == mb.id

    # <<< Cannot set an unverified mailbox as default >>>
    mb.verified = False
    Session.commit()

    r = flask_client.put(
        f"/api/mailboxes/{mb.id}",
        json={"default": True},
    )

    assert r.status_code == 400
    assert r.json == {
        "error": "Unverified mailbox cannot be used as default mailbox"
    }
Ejemplo n.º 12
0
def test_logout(flask_client):
    # create user, user is activated
    User.create(email="[email protected]",
                password="******",
                name="Test User",
                activated=True)
    Session.commit()

    # login user
    flask_client.post(
        url_for("auth.login"),
        data={
            "email": "[email protected]",
            "password": "******"
        },
        follow_redirects=True,
    )

    # logout
    r = flask_client.get(
        url_for("auth.logout"),
        follow_redirects=True,
    )

    assert r.status_code == 200
Ejemplo n.º 13
0
def reservation_route(reservation_id: int):
    reservation: PhoneReservation = PhoneReservation.get(reservation_id)
    if not reservation or reservation.user_id != current_user.id:
        flash("Unknown error, redirect back to phone page", "warning")
        return redirect(url_for("phone.index"))

    phone_number = reservation.number

    if request.method == "POST":
        if request.form.get("form-name") == "release":
            time_left = reservation.end - arrow.now()
            if time_left.seconds > 0:
                current_user.phone_quota += time_left.seconds // 60
                flash(
                    f"Your phone quota is increased by {time_left.seconds // 60} minutes",
                    "success",
                )
            reservation.end = arrow.now()
            Session.commit()

            flash(f"{phone_number.number} is released", "success")
            return redirect(url_for("phone.index"))

    return render_template(
        "phone/phone_reservation.html",
        phone_number=phone_number,
        reservation=reservation,
        now=arrow.now(),
    )
Ejemplo n.º 14
0
def send_email_at_most_times(
    user: User,
    alert_type: str,
    to_email: str,
    subject,
    plaintext,
    html=None,
    max_times=1,
) -> bool:
    """Same as send_email with rate control over alert_type.
    Sent at most `max_times`
    This is used to inform users about a warning.

    Return true if the email is sent, otherwise False
    """
    to_email = sanitize_email(to_email)
    nb_alert = SentAlert.filter_by(alert_type=alert_type,
                                   to_email=to_email).count()

    if nb_alert >= max_times:
        LOG.w(
            "%s emails were sent to %s alert type %s",
            nb_alert,
            to_email,
            alert_type,
        )
        return False

    SentAlert.create(user_id=user.id, alert_type=alert_type, to_email=to_email)
    Session.commit()
    send_email(to_email, subject, plaintext, html)
    return True
Ejemplo n.º 15
0
def app_route():
    client_users = (ClientUser.filter_by(user_id=current_user.id).options(
        joinedload(ClientUser.client)).options(joinedload(
            ClientUser.alias)).all())

    sorted(client_users, key=lambda cu: cu.client.name)

    if request.method == "POST":
        client_user_id = request.form.get("client-user-id")
        client_user = ClientUser.get(client_user_id)
        if not client_user or client_user.user_id != current_user.id:
            flash(
                "Unknown error, sorry for the inconvenience, refresh the page",
                "error")
            return redirect(request.url)

        client = client_user.client
        ClientUser.delete(client_user_id)
        Session.commit()

        flash(f"Link with {client.name}  has been removed", "success")
        return redirect(request.url)

    return render_template(
        "dashboard/app.html",
        client_users=client_users,
    )
Ejemplo n.º 16
0
def test_auth_login_device_exist(flask_client):
    User.create(email="*****@*****.**",
                password="******",
                name="Test User",
                activated=True)
    Session.commit()

    r = flask_client.post(
        url_for("api.auth_login"),
        json={
            "email": "*****@*****.**",
            "password": "******",
            "device": "Test Device",
        },
    )

    assert r.status_code == 200
    api_key = r.json["api_key"]
    assert not r.json["mfa_enabled"]
    assert r.json["mfa_key"] is None
    assert r.json["name"] == "Test User"

    # same device, should return same api_key
    r = flask_client.post(
        url_for("api.auth_login"),
        json={
            "email": "*****@*****.**",
            "password": "******",
            "device": "Test Device",
        },
    )
    assert r.json["api_key"] == api_key
Ejemplo n.º 17
0
def test_get_alias_infos_pinned_alias(flask_client):
    """Different scenarios with pinned alias"""
    user = User.create(
        email="[email protected]",
        password="******",
        name="Test User",
        activated=True,
        commit=True,
    )

    # to have 3 pages: 2*PAGE_LIMIT + the alias automatically created for a new account
    for _ in range(2 * PAGE_LIMIT):
        Alias.create_new_random(user)

    first_alias = Alias.order_by(Alias.id).first()

    # should return PAGE_LIMIT alias
    alias_infos = get_alias_infos_with_pagination_v3(user)
    assert len(alias_infos) == PAGE_LIMIT
    # make sure first_alias is not returned as the default order is alias creation date
    assert first_alias not in [ai.alias for ai in alias_infos]

    # pin the first alias
    first_alias.pinned = True
    Session.commit()

    alias_infos = get_alias_infos_with_pagination_v3(user)
    # now first_alias is the first result
    assert first_alias == alias_infos[0].alias
    # and the page size is still the same
    assert len(alias_infos) == PAGE_LIMIT

    # pinned alias isn't included in the search
    alias_infos = get_alias_infos_with_pagination_v3(user, query="no match")
    assert len(alias_infos) == 0
Ejemplo n.º 18
0
 async def delete_by_id(fizz_id: int, session: Session) -> List[int]:
     fizz = session.query(Fizz).filter(Fizz.fizz_id == fizz_id).first()
     if not fizz:
         return []
     session.delete(fizz)
     session.commit()
     return [fizz_id]
Ejemplo n.º 19
0
def test_delete_all_api_keys(flask_client):
    # create two test users
    user_1 = login(flask_client)
    user_2 = User.create(email="[email protected]",
                         password="******",
                         name="Test User 2",
                         activated=True)
    Session.commit()

    # create api_key for both users
    ApiKey.create(user_1.id, "for test")
    ApiKey.create(user_1.id, "for test 2")
    ApiKey.create(user_2.id, "for test")
    Session.commit()

    assert (ApiKey.count() == 3
            )  # assert that the total number of API keys for all users is 3.
    # assert that each user has the API keys created
    assert ApiKey.filter(ApiKey.user_id == user_1.id).count() == 2
    assert ApiKey.filter(ApiKey.user_id == user_2.id).count() == 1

    # delete all of user 1's API keys
    r = flask_client.post(
        url_for("dashboard.api_key"),
        data={"form-name": "delete-all"},
        follow_redirects=True,
    )
    assert r.status_code == 200
    assert (
        ApiKey.count() == 1
    )  # assert that the total number of API keys for all users is now 1.
    assert (ApiKey.filter(ApiKey.user_id == user_1.id).count() == 0
            )  # assert that user 1 now has 0 API keys
    assert (ApiKey.filter(ApiKey.user_id == user_2.id).count() == 1
            )  # assert that user 2 still has 1 API key
Ejemplo n.º 20
0
def test_authorize_page_login_user_non_supported_flow(flask_client):
    """return 400 if the flow is not supported"""
    user = login(flask_client)
    client = Client.create_new("test client", user.id)
    Session.commit()

    # Not provide any flow
    r = flask_client.get(
        url_for(
            "oauth.authorize",
            client_id=client.oauth_client_id,
            state="teststate",
            redirect_uri="http://localhost",
            # not provide response_type param here
        ))

    # Provide a not supported flow
    html = r.get_data(as_text=True)
    assert r.status_code == 400
    assert "SimpleLogin only support the following OIDC flows" in html

    r = flask_client.get(
        url_for(
            "oauth.authorize",
            client_id=client.oauth_client_id,
            state="teststate",
            redirect_uri="http://localhost",
            # SL does not support this flow combination
            response_type="code token id_token",
        ))

    html = r.get_data(as_text=True)
    assert r.status_code == 400
    assert "SimpleLogin only support the following OIDC flows" in html
Ejemplo n.º 21
0
def test_out_of_quota(flask_client):
    user = login(flask_client)
    user.trial_end = None
    Session.commit()

    # create MAX_NB_EMAIL_FREE_PLAN custom alias to run out of quota
    for _ in range(MAX_NB_EMAIL_FREE_PLAN):
        Alias.create_new(user, prefix="test")

    word = random_word()
    suffix = f".{word}@{EMAIL_DOMAIN}"
    signed_suffix = signer.sign(suffix).decode()

    r = flask_client.post(
        "/api/v3/alias/custom/new",
        json={
            "alias_prefix": "prefix",
            "signed_suffix": signed_suffix,
            "note": "test note",
            "mailbox_ids": [user.default_mailbox_id],
            "name": "your name",
        },
    )

    assert r.status_code == 400
    assert r.json == {
        "error":
        "You have reached the limitation of a "
        "free account with the maximum of 3 aliases, please upgrade your plan to create more aliases"
    }
Ejemplo n.º 22
0
def test_add_alias_multiple_mailboxes(flask_client):
    user = login(flask_client)
    Session.commit()

    alias_suffix = AliasSuffix(
        is_custom=False,
        suffix=f".12345@{EMAIL_DOMAIN}",
        is_premium=False,
        domain=EMAIL_DOMAIN,
    )
    signed_alias_suffix = signer.sign(alias_suffix.serialize()).decode()

    # create with a multiple mailboxes
    mb1 = Mailbox.create(user_id=user.id,
                         email="*****@*****.**",
                         verified=True)
    Session.commit()

    r = flask_client.post(
        url_for("dashboard.custom_alias"),
        data={
            "prefix": "prefix",
            "signed-alias-suffix": signed_alias_suffix,
            "mailboxes": [user.default_mailbox_id, mb1.id],
        },
        follow_redirects=True,
    )
    assert r.status_code == 200
    assert f"Alias prefix.12345@{EMAIL_DOMAIN} has been created" in str(r.data)

    alias = Alias.order_by(Alias.created_at.desc()).first()
    assert alias._mailboxes
Ejemplo n.º 23
0
def test_website_send_to(flask_client):
    user = User.create(
        email="[email protected]",
        password="******",
        name="Test User",
        activated=True,
        commit=True,
    )

    alias = Alias.create_new_random(user)
    Session.commit()

    # non-empty name
    c1 = Contact.create(
        user_id=user.id,
        alias_id=alias.id,
        website_email="*****@*****.**",
        reply_email="rep@SL",
        name="First Last",
    )
    assert c1.website_send_to(
    ) == '"First Last | abcd at example.com" <rep@SL>'

    # empty name, ascii website_from, easy case
    c1.name = None
    c1.website_from = "First Last <*****@*****.**>"
    assert c1.website_send_to(
    ) == '"First Last | abcd at example.com" <rep@SL>'

    # empty name, RFC 2047 website_from
    c1.name = None
    c1.website_from = "=?UTF-8?B?TmjGoW4gTmd1eeG7hW4=?= <*****@*****.**>"
    assert c1.website_send_to(
    ) == '"Nhơn Nguyễn | abcd at example.com" <rep@SL>'
Ejemplo n.º 24
0
def check_mailbox_valid_domain():
    """detect if there's mailbox that's using an invalid domain"""
    mailbox_ids = (Session.query(Mailbox.id).filter(
        Mailbox.verified.is_(True), Mailbox.disabled.is_(False)).all())
    mailbox_ids = [e[0] for e in mailbox_ids]
    # iterate over id instead of mailbox directly
    # as a mailbox can be deleted during the sleep time
    for mailbox_id in mailbox_ids:
        mailbox = Mailbox.get(mailbox_id)
        # a mailbox has been deleted
        if not mailbox:
            continue

        if email_can_be_used_as_mailbox(mailbox.email):
            LOG.d("Mailbox %s valid", mailbox)
            mailbox.nb_failed_checks = 0
        else:
            mailbox.nb_failed_checks += 1
            nb_email_log = nb_email_log_for_mailbox(mailbox)

            LOG.w(
                "issue with mailbox %s domain. #alias %s, nb email log %s",
                mailbox,
                mailbox.nb_alias(),
                nb_email_log,
            )

            # send a warning
            if mailbox.nb_failed_checks == 5:
                if mailbox.user.email != mailbox.email:
                    send_email(
                        mailbox.user.email,
                        f"Mailbox {mailbox.email} is disabled",
                        render(
                            "transactional/disable-mailbox-warning.txt.jinja2",
                            mailbox=mailbox,
                        ),
                        render(
                            "transactional/disable-mailbox-warning.html",
                            mailbox=mailbox,
                        ),
                        retries=3,
                    )

            # alert if too much fail and nb_email_log > 100
            if mailbox.nb_failed_checks > 10 and nb_email_log > 100:
                mailbox.disabled = True

                if mailbox.user.email != mailbox.email:
                    send_email(
                        mailbox.user.email,
                        f"Mailbox {mailbox.email} is disabled",
                        render("transactional/disable-mailbox.txt.jinja2",
                               mailbox=mailbox),
                        render("transactional/disable-mailbox.html",
                               mailbox=mailbox),
                        retries=3,
                    )

        Session.commit()
Ejemplo n.º 25
0
def block_contact(contact_id):
    contact = Contact.get(contact_id)
    if not contact:
        flash("Incorrect link. Redirect you to the home page", "warning")
        return redirect(url_for("dashboard.index"))

    if contact.user_id != current_user.id:
        flash(
            "You don't have access to this page. Redirect you to the home page",
            "warning",
        )
        return redirect(url_for("dashboard.index"))

    # automatic unsubscribe, according to https://tools.ietf.org/html/rfc8058
    if request.method == "POST":
        contact.block_forward = True
        flash(f"Emails sent from {contact.website_email} are now blocked",
              "success")
        Session.commit()

        return redirect(
            url_for(
                "dashboard.alias_contact_manager",
                alias_id=contact.alias_id,
                highlight_contact_id=contact.id,
            ))
    else:  # ask user confirmation
        return render_template("dashboard/block_contact.html", contact=contact)
Ejemplo n.º 26
0
def auth_payload(user, device) -> dict:
    ret = {
        "name": user.name or "",
        "email": user.email,
        "mfa_enabled": user.enable_otp
    }

    # do not give api_key, user can only obtain api_key after OTP verification
    if user.enable_otp:
        s = Signer(FLASK_SECRET)
        ret["mfa_key"] = s.sign(str(user.id))
        ret["api_key"] = None
    else:
        api_key = ApiKey.get_by(user_id=user.id, name=device)
        if not api_key:
            LOG.d("create new api key for %s and %s", user, device)
            api_key = ApiKey.create(user.id, device)
            Session.commit()
        ret["mfa_key"] = None
        ret["api_key"] = api_key.code

        # so user is automatically logged in on the web
        login_user(user)

    return ret
Ejemplo n.º 27
0
def test_should_disable_bounces_account(flask_client):
    """if an account has more than 10 bounces every day for at least 5 days in the last 10 days, disable alias"""
    user = login(flask_client)
    alias = Alias.create_new_random(user)

    Session.commit()

    # create a lot of bounces on alias
    contact = Contact.create(
        user_id=user.id,
        alias_id=alias.id,
        website_email="*****@*****.**",
        reply_email="*****@*****.**",
        commit=True,
    )

    for day in range(6):
        for _ in range(10):
            EmailLog.create(
                user_id=user.id,
                contact_id=contact.id,
                alias_id=contact.alias_id,
                commit=True,
                bounced=True,
                created_at=arrow.now().shift(days=-day),
            )

    alias2 = Alias.create_new_random(user)
    assert should_disable(alias2)
Ejemplo n.º 28
0
def test_handle_coinbase_event_extend_subscription(flask_client):
    user = User.create(
        email="[email protected]",
        password="******",
        name="Test User",
        activated=True,
    )
    user.trial_end = None
    Session.commit()

    cb = CoinbaseSubscription.create(user_id=user.id,
                                     end_at=arrow.now().shift(days=-400),
                                     commit=True)
    assert not cb.is_active()

    assert not user.is_paid()
    assert not user.is_premium()

    handle_coinbase_event(
        {"data": {
            "code": "AAAAAA",
            "metadata": {
                "user_id": str(user.id)
            }
        }})

    assert user.is_paid()
    assert user.is_premium()

    assert CoinbaseSubscription.get_by(user_id=user.id) is not None
Ejemplo n.º 29
0
def update_user_info():
    """
    Input
    - profile_picture (optional): base64 of the profile picture. Set to null to remove the profile picture
    - name (optional)

    """
    user = g.user
    data = request.get_json() or {}

    if "profile_picture" in data:
        if data["profile_picture"] is None:
            if user.profile_picture_id:
                file = user.profile_picture
                user.profile_picture_id = None
                Session.flush()
                if file:
                    File.delete(file.id)
                    s3.delete(file.path)
                    Session.flush()
        else:
            raw_data = base64.decodebytes(data["profile_picture"].encode())
            file_path = random_string(30)
            file = File.create(user_id=user.id, path=file_path)
            Session.flush()
            s3.upload_from_bytesio(file_path, BytesIO(raw_data))
            user.profile_picture_id = file.id
            Session.flush()

    if "name" in data:
        user.name = data["name"]

    Session.commit()

    return jsonify(user_to_dict(user))
Ejemplo n.º 30
0
def change_email():
    code = request.args.get("code")

    email_change: EmailChange = EmailChange.get_by(code=code)

    if not email_change:
        return render_template("auth/change_email.html")

    if email_change.is_expired():
        # delete the expired email
        EmailChange.delete(email_change.id)
        Session.commit()
        return render_template("auth/change_email.html")

    user = email_change.user
    user.email = email_change.new_email

    EmailChange.delete(email_change.id)
    Session.commit()

    flash("Your new email has been updated", "success")

    login_user(user)

    return redirect(url_for("dashboard.index"))