collab: Remove `GET /billing/preferences` endpoint (#34566)

Marshall Bowers created

This PR removes the `GET /billing/preferences` endpoint, as it has been
moved to `cloud.zed.dev`.

Release Notes:

- N/A

Change summary

crates/collab/src/api/billing.rs | 50 +-------------------
crates/collab/src/cents.rs       | 83 ----------------------------------
crates/collab/src/lib.rs         |  2 
crates/collab/src/llm.rs         |  8 ---
4 files changed, 3 insertions(+), 140 deletions(-)

Detailed changes

crates/collab/src/api/billing.rs 🔗

@@ -1,4 +1,5 @@
 use anyhow::{Context as _, bail};
+use axum::routing::put;
 use axum::{
     Extension, Json, Router,
     extract::{self, Query},
@@ -27,8 +28,8 @@ use crate::api::events::SnowflakeRow;
 use crate::db::billing_subscription::{
     StripeCancellationReason, StripeSubscriptionStatus, SubscriptionKind,
 };
+use crate::llm::AGENT_EXTENDED_TRIAL_FEATURE_FLAG;
 use crate::llm::db::subscription_usage_meter::{self, CompletionMode};
-use crate::llm::{AGENT_EXTENDED_TRIAL_FEATURE_FLAG, DEFAULT_MAX_MONTHLY_SPEND};
 use crate::rpc::{ResultExt as _, Server};
 use crate::stripe_client::{
     StripeCancellationDetailsReason, StripeClient, StripeCustomerId, StripeSubscription,
@@ -47,10 +48,7 @@ use crate::{
 
 pub fn router() -> Router {
     Router::new()
-        .route(
-            "/billing/preferences",
-            get(get_billing_preferences).put(update_billing_preferences),
-        )
+        .route("/billing/preferences", put(update_billing_preferences))
         .route(
             "/billing/subscriptions",
             get(list_billing_subscriptions).post(create_billing_subscription),
@@ -66,11 +64,6 @@ pub fn router() -> Router {
         .route("/billing/usage", get(get_current_usage))
 }
 
-#[derive(Debug, Deserialize)]
-struct GetBillingPreferencesParams {
-    github_user_id: i32,
-}
-
 #[derive(Debug, Serialize)]
 struct BillingPreferencesResponse {
     trial_started_at: Option<String>,
@@ -79,43 +72,6 @@ struct BillingPreferencesResponse {
     model_request_overages_spend_limit_in_cents: i32,
 }
 
-async fn get_billing_preferences(
-    Extension(app): Extension<Arc<AppState>>,
-    Query(params): Query<GetBillingPreferencesParams>,
-) -> Result<Json<BillingPreferencesResponse>> {
-    let user = app
-        .db
-        .get_user_by_github_user_id(params.github_user_id)
-        .await?
-        .context("user not found")?;
-
-    let billing_customer = app.db.get_billing_customer_by_user_id(user.id).await?;
-    let preferences = app.db.get_billing_preferences(user.id).await?;
-
-    Ok(Json(BillingPreferencesResponse {
-        trial_started_at: billing_customer
-            .and_then(|billing_customer| billing_customer.trial_started_at)
-            .map(|trial_started_at| {
-                trial_started_at
-                    .and_utc()
-                    .to_rfc3339_opts(SecondsFormat::Millis, true)
-            }),
-        max_monthly_llm_usage_spending_in_cents: preferences
-            .as_ref()
-            .map_or(DEFAULT_MAX_MONTHLY_SPEND.0 as i32, |preferences| {
-                preferences.max_monthly_llm_usage_spending_in_cents
-            }),
-        model_request_overages_enabled: preferences.as_ref().map_or(false, |preferences| {
-            preferences.model_request_overages_enabled
-        }),
-        model_request_overages_spend_limit_in_cents: preferences
-            .as_ref()
-            .map_or(0, |preferences| {
-                preferences.model_request_overages_spend_limit_in_cents
-            }),
-    }))
-}
-
 #[derive(Debug, Deserialize)]
 struct UpdateBillingPreferencesBody {
     github_user_id: i32,

crates/collab/src/cents.rs 🔗

@@ -1,83 +0,0 @@
-use serde::Serialize;
-
-/// A number of cents.
-#[derive(
-    Debug,
-    PartialEq,
-    Eq,
-    PartialOrd,
-    Ord,
-    Hash,
-    Clone,
-    Copy,
-    derive_more::Add,
-    derive_more::AddAssign,
-    derive_more::Sub,
-    derive_more::SubAssign,
-    Serialize,
-)]
-pub struct Cents(pub u32);
-
-impl Cents {
-    pub const ZERO: Self = Self(0);
-
-    pub const fn new(cents: u32) -> Self {
-        Self(cents)
-    }
-
-    pub const fn from_dollars(dollars: u32) -> Self {
-        Self(dollars * 100)
-    }
-
-    pub fn saturating_sub(self, other: Cents) -> Self {
-        Self(self.0.saturating_sub(other.0))
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use pretty_assertions::assert_eq;
-
-    use super::*;
-
-    #[test]
-    fn test_cents_new() {
-        assert_eq!(Cents::new(50), Cents(50));
-    }
-
-    #[test]
-    fn test_cents_from_dollars() {
-        assert_eq!(Cents::from_dollars(1), Cents(100));
-        assert_eq!(Cents::from_dollars(5), Cents(500));
-    }
-
-    #[test]
-    fn test_cents_zero() {
-        assert_eq!(Cents::ZERO, Cents(0));
-    }
-
-    #[test]
-    fn test_cents_add() {
-        assert_eq!(Cents(50) + Cents(30), Cents(80));
-    }
-
-    #[test]
-    fn test_cents_add_assign() {
-        let mut cents = Cents(50);
-        cents += Cents(30);
-        assert_eq!(cents, Cents(80));
-    }
-
-    #[test]
-    fn test_cents_saturating_sub() {
-        assert_eq!(Cents(50).saturating_sub(Cents(30)), Cents(20));
-        assert_eq!(Cents(30).saturating_sub(Cents(50)), Cents(0));
-    }
-
-    #[test]
-    fn test_cents_ordering() {
-        assert!(Cents(50) > Cents(30));
-        assert!(Cents(30) < Cents(50));
-        assert_eq!(Cents(50), Cents(50));
-    }
-}

crates/collab/src/lib.rs 🔗

@@ -1,6 +1,5 @@
 pub mod api;
 pub mod auth;
-mod cents;
 pub mod db;
 pub mod env;
 pub mod executor;
@@ -21,7 +20,6 @@ use axum::{
     http::{HeaderMap, StatusCode},
     response::IntoResponse,
 };
-pub use cents::*;
 use db::{ChannelId, Database};
 use executor::Executor;
 use llm::db::LlmDatabase;

crates/collab/src/llm.rs 🔗

@@ -1,8 +1,6 @@
 pub mod db;
 mod token;
 
-use crate::Cents;
-
 pub use token::*;
 
 pub const AGENT_EXTENDED_TRIAL_FEATURE_FLAG: &str = "agent-extended-trial";
@@ -12,9 +10,3 @@ pub const BYPASS_ACCOUNT_AGE_CHECK_FEATURE_FLAG: &str = "bypass-account-age-chec
 
 /// The minimum account age an account must have in order to use the LLM service.
 pub const MIN_ACCOUNT_AGE_FOR_LLM_USE: chrono::Duration = chrono::Duration::days(30);
-
-/// The default value to use for maximum spend per month if the user did not
-/// explicitly set a maximum spend.
-///
-/// Used to prevent surprise bills.
-pub const DEFAULT_MAX_MONTHLY_SPEND: Cents = Cents::from_dollars(10);