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)
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
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)