This commit is contained in:
Andras Schmelczer 2026-02-18 21:22:15 +00:00
parent 524580eb25
commit ffe080adef
82 changed files with 2652 additions and 2956 deletions

View file

@ -18,10 +18,21 @@ struct CollectionItem {
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct CreateCollection {
name: String,
r#type: String,
fields: Vec<Field>,
#[serde(skip_serializing_if = "Option::is_none")]
list_rule: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
view_rule: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
create_rule: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
update_rule: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
delete_rule: Option<String>,
}
#[derive(Serialize)]
@ -251,6 +262,37 @@ async fn ensure_user_fields(
Ok(())
}
/// Ensure the `saved_searches` collection has API rules allowing users to manage their own records.
async fn ensure_saved_searches_rules(
client: &Client,
base_url: &str,
token: &str,
) -> anyhow::Result<()> {
let url = format!("{base_url}/api/collections/saved_searches");
let user_only = "user = @request.auth.id";
let resp = client
.patch(&url)
.header("Authorization", format!("Bearer {token}"))
.json(&serde_json::json!({
"listRule": user_only,
"viewRule": user_only,
"createRule": user_only,
"updateRule": user_only,
"deleteRule": user_only,
}))
.send()
.await?;
if !resp.status().is_success() {
let status = resp.status();
let text = resp.text().await.unwrap_or_default();
anyhow::bail!("Failed to update saved_searches API rules ({status}): {text}");
}
info!("PocketBase collection 'saved_searches' API rules updated");
Ok(())
}
/// Ensure the `saved_searches` and `short_urls` collections exist in PocketBase,
/// and that the `users` collection has `is_admin` and `subscription` fields.
/// Authenticates as superuser, checks existing collections, and creates any that are missing.
@ -269,6 +311,7 @@ pub async fn ensure_collections(
if !existing.iter().any(|n| n == "saved_searches") {
let users_id = find_users_collection_id(client, base_url, &token).await?;
let user_only = Some("user = @request.auth.id".to_string());
create_collection(
client,
base_url,
@ -282,11 +325,16 @@ pub async fn ensure_collections(
Field::text("params", true),
Field::file("screenshot", vec!["image/png", "image/jpeg", "image/webp"]),
],
list_rule: user_only.clone(),
view_rule: user_only.clone(),
create_rule: user_only.clone(),
update_rule: user_only.clone(),
delete_rule: user_only,
},
)
.await?;
} else {
info!("PocketBase collection 'saved_searches' already exists");
ensure_saved_searches_rules(client, base_url, &token).await?;
}
if !existing.iter().any(|n| n == "invites") {
@ -304,6 +352,11 @@ pub async fn ensure_collections(
Field::text("used_by_id", false),
Field::text("used_at", false),
],
list_rule: None,
view_rule: None,
create_rule: None,
update_rule: None,
delete_rule: None,
},
)
.await?;
@ -323,6 +376,11 @@ pub async fn ensure_collections(
Field::text("code", true),
Field::text("params", true),
],
list_rule: None,
view_rule: None,
create_rule: None,
update_rule: None,
delete_rule: None,
},
)
.await?;
@ -333,7 +391,7 @@ pub async fn ensure_collections(
Ok(())
}
/// Configure Google and Apple OAuth2 providers in PocketBase settings.
/// Configure Google OAuth2 provider in PocketBase settings.
/// Also sets `meta.appUrl` so OAuth callbacks route to `{public_url}/pb`.
pub async fn ensure_oauth_providers(
client: &Client,
@ -343,8 +401,6 @@ pub async fn ensure_oauth_providers(
public_url: &str,
google_client_id: &str,
google_client_secret: &str,
apple_client_id: &str,
apple_client_secret: &str,
) -> anyhow::Result<()> {
let base_url = base_url.trim_end_matches('/');
let token = auth_superuser(client, base_url, admin_email, admin_password).await?;
@ -392,12 +448,6 @@ pub async fn ensure_oauth_providers(
provider["enabled"] = serde_json::json!(true);
info!("Configured Google OAuth provider");
}
"apple" => {
provider["clientId"] = serde_json::json!(apple_client_id);
provider["clientSecret"] = serde_json::json!(apple_client_secret);
provider["enabled"] = serde_json::json!(true);
info!("Configured Apple OAuth provider");
}
_ => {}
}
}