Beispiel #1
0
def login_or_register_remote_user(request: HttpRequest,
                                  result: ExternalAuthResult) -> HttpResponse:
    """Given a successful authentication showing the user controls given
    email address (email) and potentially a UserProfile
    object (if the user already has a Zulip account), redirect the
    browser to the appropriate place:

    * The logged-in app if the user already has a Zulip account and is
      trying to log in, potentially to an initial narrow or page that had been
      saved in the `redirect_to` parameter.
    * The registration form if is_signup was set (i.e. the user is
      trying to create a Zulip account)
    * A special `confirm_continue_registration.html` "do you want to
      register or try another account" if the user doesn't have a
      Zulip account but is_signup is False (i.e. the user tried to log in
      and then did social authentication selecting an email address that does
      not have a Zulip account in this organization).
    * A zulip:// URL to send control back to the mobile or desktop apps if they
      are doing authentication using the mobile_flow_otp or desktop_flow_otp flow.
    """
    user_profile = result.user_profile
    if user_profile is None or user_profile.is_mirror_dummy:
        return register_remote_user(request, result)
    # Otherwise, the user has successfully authenticated to an
    # account, and we need to do the right thing depending whether
    # or not they're using the mobile OTP flow or want a browser session.
    is_realm_creation = result.data_dict.get("is_realm_creation")
    mobile_flow_otp = result.data_dict.get("mobile_flow_otp")
    desktop_flow_otp = result.data_dict.get("desktop_flow_otp")
    if mobile_flow_otp is not None:
        return finish_mobile_flow(request, user_profile, mobile_flow_otp)
    elif desktop_flow_otp is not None:
        return finish_desktop_flow(request, user_profile, desktop_flow_otp)

    do_login(request, user_profile)

    redirect_to = result.data_dict.get("redirect_to", "")
    if is_realm_creation is not None and settings.BILLING_ENABLED:
        from corporate.lib.stripe import is_free_trial_offer_enabled

        if is_free_trial_offer_enabled():
            redirect_to = "{}?onboarding=true".format(
                reverse("initial_upgrade"))

    redirect_to = get_safe_redirect_to(redirect_to, user_profile.realm.uri)
    return HttpResponseRedirect(redirect_to)
Beispiel #2
0
def setup_upgrade_checkout_session_and_payment_intent(
    user: UserProfile,
    seat_count: int,
    licenses: int,
    license_management: str,
    billing_schedule: int,
    billing_modality: str,
    onboarding: bool,
) -> stripe.checkout.Session:
    customer = update_or_create_stripe_customer(user)
    assert customer is not None  # for mypy
    free_trial = is_free_trial_offer_enabled()
    _, _, _, price_per_license = compute_plan_parameters(
        CustomerPlan.STANDARD,
        license_management == "automatic",
        billing_schedule,
        customer.default_discount,
        free_trial,
    )
    metadata = {
        "billing_modality": billing_modality,
        "billing_schedule": billing_schedule,
        "licenses": licenses,
        "license_management": license_management,
        "price_per_license": price_per_license,
        "seat_count": seat_count,
        "type": "upgrade",
        "user_email": user.delivery_email,
        "realm_id": user.realm.id,
        "realm_str": user.realm.string_id,
        "user_id": user.id,
    }
    if free_trial:
        if onboarding:
            session_type = Session.FREE_TRIAL_UPGRADE_FROM_ONBOARDING_PAGE
        else:
            session_type = Session.FREE_TRIAL_UPGRADE_FROM_BILLING_PAGE
        payment_intent = None
    else:
        session_type = Session.UPGRADE_FROM_BILLING_PAGE
        stripe_payment_intent = stripe.PaymentIntent.create(
            amount=price_per_license * licenses,
            currency="usd",
            customer=customer.stripe_customer_id,
            description=
            f"Upgrade to Zulip Cloud Standard, ${price_per_license/100} x {licenses}",
            receipt_email=user.delivery_email,
            confirm=False,
            statement_descriptor="Zulip Cloud Standard",
            metadata=metadata,
        )
        payment_intent = PaymentIntent.objects.create(
            customer=customer,
            stripe_payment_intent_id=stripe_payment_intent.id,
            status=PaymentIntent.get_status_integer_from_status_text(
                stripe_payment_intent.status),
        )
    stripe_session = stripe.checkout.Session.create(
        cancel_url=f"{user.realm.uri}/upgrade/",
        customer=customer.stripe_customer_id,
        mode="setup",
        payment_method_types=["card"],
        metadata=metadata,
        setup_intent_data={"metadata": metadata},
        success_url=
        f"{user.realm.uri}/billing/event_status?stripe_session_id={{CHECKOUT_SESSION_ID}}",
    )
    session = Session.objects.create(customer=customer,
                                     stripe_session_id=stripe_session.id,
                                     type=session_type)
    if payment_intent is not None:
        session.payment_intent = payment_intent
        session.save(update_fields=["payment_intent"])
    return stripe_session
Beispiel #3
0
def upgrade(
    request: HttpRequest,
    user: UserProfile,
    billing_modality: str = REQ(
        str_validator=check_string_in(VALID_BILLING_MODALITY_VALUES)),
    schedule: str = REQ(
        str_validator=check_string_in(VALID_BILLING_SCHEDULE_VALUES)),
    signed_seat_count: str = REQ(),
    salt: str = REQ(),
    onboarding: bool = REQ(default=False, json_validator=check_bool),
    license_management: Optional[str] = REQ(
        default=None,
        str_validator=check_string_in(VALID_LICENSE_MANAGEMENT_VALUES)),
    licenses: Optional[int] = REQ(json_validator=check_int, default=None),
) -> HttpResponse:
    ensure_realm_does_not_have_active_plan(user.realm)
    try:
        seat_count = unsign_seat_count(signed_seat_count, salt)
        if billing_modality == "charge_automatically" and license_management == "automatic":
            licenses = seat_count
        if billing_modality == "send_invoice":
            schedule = "annual"
            license_management = "manual"
        check_upgrade_parameters(billing_modality, schedule,
                                 license_management, licenses, seat_count)
        assert licenses is not None and license_management is not None
        automanage_licenses = license_management == "automatic"
        charge_automatically = billing_modality == "charge_automatically"

        billing_schedule = {
            "annual": CustomerPlan.ANNUAL,
            "monthly": CustomerPlan.MONTHLY
        }[schedule]
        if charge_automatically:
            stripe_checkout_session = setup_upgrade_checkout_session_and_payment_intent(
                user,
                seat_count,
                licenses,
                license_management,
                billing_schedule,
                billing_modality,
                onboarding,
            )
            return json_success(
                request,
                data={
                    "stripe_session_url": stripe_checkout_session.url,
                    "stripe_session_id": stripe_checkout_session.id,
                },
            )
        else:
            process_initial_upgrade(
                user,
                licenses,
                automanage_licenses,
                billing_schedule,
                False,
                is_free_trial_offer_enabled(),
            )
            return json_success(request)

    except BillingError as e:
        billing_logger.warning(
            "BillingError during upgrade: %s. user=%s, realm=%s (%s), billing_modality=%s, "
            "schedule=%s, license_management=%s, licenses=%s",
            e.error_description,
            user.id,
            user.realm.id,
            user.realm.string_id,
            billing_modality,
            schedule,
            license_management,
            licenses,
        )
        raise e
    except Exception:
        billing_logger.exception("Uncaught exception in billing:",
                                 stack_info=True)
        error_message = BillingError.CONTACT_SUPPORT.format(
            email=settings.ZULIP_ADMINISTRATOR)
        error_description = "uncaught exception during upgrade"
        raise BillingError(error_description, error_message)