/home/josie/development/irc-now/crates/web-api/templates/admin_user_detail.html-10-
sub
{{ user.sub }}
/home/josie/development/irc-now/crates/web-api/templates/admin_user_detail.html-11-
email
{{ user.email }}
/home/josie/development/irc-now/crates/web-api/templates/admin_user_detail.html-12-
display name
{{ user.display_name }}
/home/josie/development/irc-now/crates/web-api/templates/admin_user_detail.html:13:
plan
{{ user.plan }}
/home/josie/development/irc-now/crates/web-api/templates/admin_user_detail.html-14-
admin
{% if user.is_admin %}yes{% else %}no{% endif %}
/home/josie/development/irc-now/crates/web-api/templates/admin_user_detail.html-15-
status
{% if user.suspended %}suspended{% else %}active{% endif %}
/home/josie/development/irc-now/crates/web-api/templates/admin_user_detail.html-16- {% if user.suspended %} -- /home/josie/development/irc-now/crates/web-api/templates/profile.html-34- change password /home/josie/development/irc-now/crates/web-api/templates/profile.html-35- /home/josie/development/irc-now/crates/web-api/templates/profile.html-36- /home/josie/development/irc-now/crates/web-api/templates/profile.html:37: {% if plan == "pro" %} /home/josie/development/irc-now/crates/web-api/templates/profile.html-38-
/home/josie/development/irc-now/crates/web-api/templates/profile.html-40- -- /home/josie/development/irc-now/crates/web-api/templates/profile.html-60-
/home/josie/development/irc-now/crates/web-api/templates/profile.html-61-

account

/home/josie/development/irc-now/crates/web-api/templates/profile.html-62-
/home/josie/development/irc-now/crates/web-api/templates/profile.html:63: plan /home/josie/development/irc-now/crates/web-api/templates/profile.html:64: {{ plan }} /home/josie/development/irc-now/crates/web-api/templates/profile.html-65-
/home/josie/development/irc-now/crates/web-api/templates/profile.html-66-
/home/josie/development/irc-now/crates/web-api/templates/profile.html-67- id -- /home/josie/development/irc-now/crates/web-api/templates/admin_users.html-18- /home/josie/development/irc-now/crates/web-api/templates/admin_users.html-19- /home/josie/development/irc-now/crates/web-api/templates/admin_users.html-20- email /home/josie/development/irc-now/crates/web-api/templates/admin_users.html:21: plan /home/josie/development/irc-now/crates/web-api/templates/admin_users.html-22- status /home/josie/development/irc-now/crates/web-api/templates/admin_users.html-23- created /home/josie/development/irc-now/crates/web-api/templates/admin_users.html-24- -- /home/josie/development/irc-now/crates/web-api/templates/admin_users.html-28- {% for u in users %} /home/josie/development/irc-now/crates/web-api/templates/admin_users.html-29- /home/josie/development/irc-now/crates/web-api/templates/admin_users.html-30- {{ u.email }} /home/josie/development/irc-now/crates/web-api/templates/admin_users.html:31: {{ u.plan }} /home/josie/development/irc-now/crates/web-api/templates/admin_users.html-32- {% if u.suspended %}suspended{% else %}active{% endif %} /home/josie/development/irc-now/crates/web-api/templates/admin_users.html-33- {{ u.created_at }} /home/josie/development/irc-now/crates/web-api/templates/admin_users.html-34- view -- /home/josie/development/irc-now/crates/web-api/templates/dashboard.html-15-
/home/josie/development/irc-now/crates/web-api/templates/dashboard.html-16- /home/josie/development/irc-now/crates/web-api/templates/dashboard.html-17-
/home/josie/development/irc-now/crates/web-api/templates/dashboard.html:18:

plan

/home/josie/development/irc-now/crates/web-api/templates/dashboard.html:19:

{{ plan }}

/home/josie/development/irc-now/crates/web-api/templates/dashboard.html-20- {% if !is_pro %} /home/josie/development/irc-now/crates/web-api/templates/dashboard.html-21- upgrade to pro /home/josie/development/irc-now/crates/web-api/templates/dashboard.html-22- {% endif %} -- /home/josie/development/irc-now/crates/web-api/templates/dashboard.html-75- {% endif %} /home/josie/development/irc-now/crates/web-api/templates/dashboard.html-76- {% else %} /home/josie/development/irc-now/crates/web-api/templates/dashboard.html-77-

shared bouncer

/home/josie/development/irc-now/crates/web-api/templates/dashboard.html:78:

your free plan includes access to the shared bouncer via web chat.

/home/josie/development/irc-now/crates/web-api/templates/dashboard.html-79-
/home/josie/development/irc-now/crates/web-api/templates/dashboard.html-80- chat.irc.now /home/josie/development/irc-now/crates/web-api/templates/dashboard.html-81- upgrade to pro -- /home/josie/development/irc-now/crates/web-api/templates/billing.html-8-
/home/josie/development/irc-now/crates/web-api/templates/billing.html-9-

billing

/home/josie/development/irc-now/crates/web-api/templates/billing.html-10-
/home/josie/development/irc-now/crates/web-api/templates/billing.html:11:

current plan

/home/josie/development/irc-now/crates/web-api/templates/billing.html:12:

{{ plan }}

/home/josie/development/irc-now/crates/web-api/templates/billing.html-13- {% if is_pro %} /home/josie/development/irc-now/crates/web-api/templates/billing.html-14- manage subscription /home/josie/development/irc-now/crates/web-api/templates/billing.html-15- {% else %} -- /home/josie/development/irc-now/crates/web-api/src/auth_guard.rs-34- }; /home/josie/development/irc-now/crates/web-api/src/auth_guard.rs-35- /home/josie/development/irc-now/crates/web-api/src/auth_guard.rs-36- let suspended: Option = sqlx::query_scalar( /home/josie/development/irc-now/crates/web-api/src/auth_guard.rs:37: "SELECT suspended_at IS NOT NULL FROM users WHERE keycloak_sub = $1", /home/josie/development/irc-now/crates/web-api/src/auth_guard.rs-38- ) /home/josie/development/irc-now/crates/web-api/src/auth_guard.rs-39- .bind(&claims.sub) /home/josie/development/irc-now/crates/web-api/src/auth_guard.rs-40- .fetch_optional(&state.db) -- /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-55- } /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-56- /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-57- let upgrades_30d: i64 = sqlx::query_scalar( /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs:58: "SELECT COUNT(*) FROM events WHERE event_type = 'plan_upgrade' AND created_at > NOW() - INTERVAL '30 days'", /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-59- ) /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-60- .fetch_one(&db) /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-61- .await -- /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-76- gauge!("irc_now_conversion_rate_30d").set(conversion_rate); /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-77- /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-78- let downgrades_30d: i64 = sqlx::query_scalar( /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs:79: "SELECT COUNT(*) FROM events WHERE event_type = 'plan_downgrade' AND created_at > NOW() - INTERVAL '30 days'", /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-80- ) /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-81- .fetch_one(&db) /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-82- .await /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-83- .unwrap_or(0); /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-84- /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-85- let pro_users: i64 = sqlx::query_scalar( /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs:86: "SELECT COUNT(*) FROM users WHERE plan = 'pro'", /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-87- ) /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-88- .fetch_one(&db) /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-89- .await -- /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-106- } /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-107- /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-108- if let Ok(rows) = sqlx::query_as::<_, (String, i64)>( /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs:109: "SELECT plan, COUNT(*) FROM users GROUP BY plan", /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-110- ) /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-111- .fetch_all(&db) /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-112- .await /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-113- { /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs:114: for (plan, count) in rows { /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs:115: gauge!("irc_now_users_by_plan", "plan" => plan).set(count as f64); /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-116- } /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-117- } /home/josie/development/irc-now/crates/web-api/src/business_metrics.rs-118- } -- /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-16-#[template(path = "billing.html")] /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-17-pub struct BillingTemplate { /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-18- pub page: PageContext, /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs:19: pub plan: String, /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-20- pub is_pro: bool, /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-21-} /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-22- -- /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-25- headers: HeaderMap, /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-26- AuthUser(user): AuthUser, /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-27-) -> impl IntoResponse { /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs:28: let plan = user.plan.unwrap_or_else(|| "free".to_string()); /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs:29: let is_pro = plan == "pro"; /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-30- /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-31- let page = PageContext::from_request(&headers, &state.announcement); /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-32- let clear = page.flash.is_some(); /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-33- /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs:34: let template = BillingTemplate { page, plan, is_pro }; /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-35- /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-36- if clear { /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-37- (axum::response::AppendHeaders([flash::clear_flash()]), template).into_response() -- /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-63- } /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-64- /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-65- let mut metadata = std::collections::HashMap::new(); /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs:66: metadata.insert("keycloak_sub".to_string(), user.sub.clone()); /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-67- params.metadata = Some(metadata); /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-68- /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-69- let session = match stripe::CheckoutSession::create(&state.stripe_client, params).await { -- /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-148- let customer = event.data.object.get("customer") /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-149- .and_then(|v| v.as_str()); /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-150- let sub = event.data.object.get("metadata") /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs:151: .and_then(|m| m.get("keycloak_sub")) /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-152- .and_then(|v| v.as_str()); /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-153- /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-154- if let (Some(customer), Some(sub)) = (customer, sub) { /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-155- let result = sqlx::query( /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs:156: "UPDATE users SET plan = 'pro', stripe_customer_id = $1 WHERE keycloak_sub = $2 AND plan != 'pro'", /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-157- ) /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-158- .bind(customer) /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-159- .bind(sub) -- /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-169- tracing::warn!("keycloak attribute sync after upgrade failed: {e}"); /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-170- } /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-171- crate::events::record( /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs:172: &state.db, sub, "plan_upgrade", /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-173- Some(serde_json::json!({"from": "free", "to": "pro"})), /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-174- ).await; /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-175- } -- /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-183- /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-184- if let Some(customer) = customer { /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-185- let sub: Option = sqlx::query_scalar( /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs:186: "UPDATE users SET plan = 'free' WHERE stripe_customer_id = $1 RETURNING keycloak_sub", /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-187- ) /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-188- .bind(customer) /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-189- .fetch_optional(&state.db) -- /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-195- tracing::warn!("keycloak attribute sync after downgrade failed: {e}"); /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-196- } /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-197- crate::events::record( /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs:198: &state.db, &sub, "plan_downgrade", /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-199- Some(serde_json::json!({"from": "pro", "to": "free"})), /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-200- ).await; /home/josie/development/irc-now/crates/web-api/src/routes/billing.rs-201- } -- /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-332- /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-333-#[derive(FromRow)] /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-334-struct UserSearchRow { /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs:335: keycloak_sub: String, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-336- email: Option, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs:337: plan: String, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-338- is_admin: bool, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-339- suspended_at: Option>, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-340- created_at: Option>, -- /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-344-pub struct UserSearchEntry { /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-345- pub sub: String, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-346- pub email: String, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs:347: pub plan: String, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-348- pub is_admin: bool, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-349- pub suspended: bool, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-350- pub created_at: String, -- /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-374- /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-375- let rows = if query.is_empty() { /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-376- sqlx::query_as::<_, UserSearchRow>( /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs:377: "SELECT keycloak_sub, email, plan, is_admin, suspended_at, created_at /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-378- FROM users ORDER BY created_at DESC LIMIT 50", /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-379- ) /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-380- .fetch_all(&state.db) /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-381- .await /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-382- } else { /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-383- sqlx::query_as::<_, UserSearchRow>( /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs:384: "SELECT keycloak_sub, email, plan, is_admin, suspended_at, created_at /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs:385: FROM users WHERE email ILIKE $1 OR keycloak_sub = $2 /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-386- ORDER BY created_at DESC LIMIT 50", /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-387- ) /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-388- .bind(format!("%{query}%")) -- /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-399- let users = rows /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-400- .into_iter() /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-401- .map(|r| UserSearchEntry { /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs:402: sub: r.keycloak_sub, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-403- email: r.email.unwrap_or_default(), /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs:404: plan: r.plan, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-405- is_admin: r.is_admin, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-406- suspended: r.suspended_at.is_some(), /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-407- created_at: r -- /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-416- /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-417-#[derive(FromRow)] /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-418-struct UserDetailRow { /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs:419: keycloak_sub: String, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-420- email: Option, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs:421: plan: String, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-422- display_name: Option, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-423- is_admin: bool, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-424- suspended_at: Option>, -- /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-438- pub sub: String, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-439- pub email: String, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-440- pub display_name: String, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs:441: pub plan: String, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-442- pub is_admin: bool, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-443- pub suspended: bool, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-444- pub suspended_reason: String, -- /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-455- let clear = page.flash.is_some(); /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-456- /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-457- let row = sqlx::query_as::<_, UserDetailRow>( /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs:458: "SELECT keycloak_sub, email, plan, display_name, is_admin, suspended_at, suspended_reason, created_at /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs:459: FROM users WHERE keycloak_sub = $1", /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-460- ) /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-461- .bind(&sub) /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-462- .fetch_optional(&state.db) -- /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-478- let template = AdminUserDetailTemplate { /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-479- page, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-480- user: UserDetailView { /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs:481: sub: row.keycloak_sub, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-482- email: row.email.unwrap_or_default(), /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-483- display_name: row.display_name.unwrap_or_default(), /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs:484: plan: row.plan, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-485- is_admin: row.is_admin, /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-486- suspended: row.suspended_at.is_some(), /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-487- suspended_reason: row.suspended_reason.unwrap_or_default(), -- /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-519- } /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-520- /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-521- let _ = sqlx::query( /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs:522: "UPDATE users SET suspended_at = NOW(), suspended_reason = $1 WHERE keycloak_sub = $2", /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-523- ) /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-524- .bind(&reason) /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-525- .bind(&sub) -- /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-553- } /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-554- /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-555- let _ = sqlx::query( /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs:556: "UPDATE users SET suspended_at = NULL, suspended_reason = NULL WHERE keycloak_sub = $1", /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-557- ) /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-558- .bind(&sub) /home/josie/development/irc-now/crates/web-api/src/routes/admin.rs-559- .execute(&state.db) -- /home/josie/development/irc-now/crates/web-api/src/routes/bot.rs-214- /home/josie/development/irc-now/crates/web-api/src/routes/bot.rs-215- let body = serde_json::json!({ /home/josie/development/irc-now/crates/web-api/src/routes/bot.rs-216- "user_id": user.sub, /home/josie/development/irc-now/crates/web-api/src/routes/bot.rs:217: "plan": user.plan.as_deref().unwrap_or("free"), /home/josie/development/irc-now/crates/web-api/src/routes/bot.rs-218- "name": form.name.trim(), /home/josie/development/irc-now/crates/web-api/src/routes/bot.rs-219- "nick": nick, /home/josie/development/irc-now/crates/web-api/src/routes/bot.rs-220- "network_addr": network_addr, -- /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-40- /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-41-#[derive(FromRow)] /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-42-struct UserRow { /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs:43: plan: String, /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-44- stripe_customer_id: Option, /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-45- display_name: Option, /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-46- content_expires: bool, -- /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-150- let email = payload.userinfo.email.as_deref(); /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-151- /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-152- let row = sqlx::query_as::<_, UserRow>( /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs:153: "INSERT INTO users (keycloak_sub, email) /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-154- VALUES ($1, $2) /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs:155: ON CONFLICT (keycloak_sub) DO UPDATE SET email = EXCLUDED.email, last_login_at = NOW() /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs:156: RETURNING plan, stripe_customer_id, display_name, content_expires, is_admin, created_at, (xmax = 0) AS is_new", /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-157- ) /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-158- .bind(sub) /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-159- .bind(email) -- /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-174- let claims = UserClaims { /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-175- sub: sub.clone(), /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-176- email: email.map(String::from), /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs:177: plan: Some(row.plan.clone()), /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-178- stripe_customer_id: row.stripe_customer_id, /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-179- display_name: row.display_name, /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-180- content_expires: Some(row.content_expires), -- /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-184- if let Err(e) = update_keycloak_user_attributes( /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-185- &state, /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-186- sub, /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs:187: &row.plan, /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-188- row.content_expires, /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-189- ) /home/josie/development/irc-now/crates/web-api/src/routes/auth.rs-190- .await -- /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-19-struct ProfileRow { /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-20- email: Option, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-21- display_name: Option, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs:22: plan: String, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-23- created_at: String, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-24- content_expires: bool, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-25-} -- /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-30- pub page: PageContext, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-31- pub display_name: String, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-32- pub email: String, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs:33: pub plan: String, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-34- pub sub: String, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-35- pub created_at: String, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-36- pub password_url: String, -- /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-43- AuthUser(user): AuthUser, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-44-) -> Result { /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-45- let row = sqlx::query_as::<_, ProfileRow>( /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs:46: "SELECT email, display_name, plan, to_char(created_at, 'YYYY-MM-DD') AS created_at, content_expires FROM users WHERE keycloak_sub = $1", /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-47- ) /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-48- .bind(&user.sub) /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-49- .fetch_one(&state.db) -- /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-65- page, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-66- display_name: row.display_name.unwrap_or_default(), /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-67- email: row.email.unwrap_or_default(), /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs:68: plan: row.plan, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-69- sub: user.sub, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-70- created_at: row.created_at, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-71- password_url, -- /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-121- }; /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-122- /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-123- let result = sqlx::query( /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs:124: "UPDATE users SET display_name = $1, email = $2, content_expires = $3 WHERE keycloak_sub = $4", /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-125- ) /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-126- .bind(display_name_val) /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-127- .bind(&new_email) -- /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-135- return flash_response(&headers, "profile_save_failed", "/profile"); /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-136- } /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-137- /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs:138: let plan_str = user.plan.as_deref().unwrap_or("free"); /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-139- if let Err(e) = update_keycloak_user_attributes( /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-140- &state, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-141- &user.sub, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs:142: plan_str, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-143- content_expires, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-144- ) /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-145- .await -- /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-154- } else { /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-155- Some(new_email) /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-156- }, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs:157: plan: user.plan, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-158- stripe_customer_id: user.stripe_customer_id, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-159- display_name: if display_name.is_empty() { /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-160- None -- /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-187-pub(crate) async fn update_keycloak_user_attributes( /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-188- state: &AppState, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-189- sub: &str, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs:190: plan: &str, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-191- content_expires: bool, /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-192-) -> Result<(), String> { /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-193- let token = crate::keycloak::get_admin_token(state).await?; -- /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-208- .bearer_auth(&token) /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-209- .json(&serde_json::json!({ /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-210- "attributes": { /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs:211: "plan": [plan], /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-212- "content_expires": [content_expires.to_string()] /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-213- } /home/josie/development/irc-now/crates/web-api/src/routes/profile.rs-214- })) -- /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs-20- pub has_bouncer: bool, /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs-21- pub bouncer_ready: bool, /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs-22- pub is_pro: bool, /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs:23: pub plan: String, /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs-24- pub networks: i64, /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs-25- pub channels: i64, /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs-26- pub messages_relayed: i64, -- /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs-92- .map(|c| c.status == "True") /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs-93- .unwrap_or(false); /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs-94- /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs:95: let plan = user.plan.unwrap_or_else(|| "free".to_string()); /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs:96: let is_pro = plan == "pro"; /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs-97- /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs-98- let (mut networks, mut channels, mut messages_relayed) = (0i64, 0i64, 0i64); /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs-99- let mut bouncer_uptime = "--".to_string(); -- /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs-153- has_bouncer, /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs-154- bouncer_ready, /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs-155- is_pro, /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs:156: plan, /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs-157- networks, /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs-158- channels, /home/josie/development/irc-now/crates/web-api/src/routes/dashboard.rs-159- messages_relayed,