mirror of https://github.com/buster-so/buster.git
add in supabase helper
This commit is contained in:
parent
4c052e0c03
commit
0686febbfb
|
@ -25,6 +25,8 @@ tokio-postgres = { workspace = true }
|
||||||
tokio-postgres-rustls = { workspace = true }
|
tokio-postgres-rustls = { workspace = true }
|
||||||
bb8-redis = { workspace = true }
|
bb8-redis = { workspace = true }
|
||||||
serde_yaml = { workspace = true }
|
serde_yaml = { workspace = true }
|
||||||
|
dotenv = { workspace = true }
|
||||||
|
reqwest = { workspace = true }
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -5,5 +5,7 @@ pub mod schema;
|
||||||
pub mod vault;
|
pub mod vault;
|
||||||
pub mod helpers;
|
pub mod helpers;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
pub mod supabase;
|
||||||
|
|
||||||
pub use helpers::*;
|
pub use helpers::*;
|
||||||
|
pub use supabase::*;
|
|
@ -0,0 +1,168 @@
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
use dotenv::dotenv;
|
||||||
|
use reqwest::{Client, Error};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
// Structs for JSON payloads and responses
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
struct CreateUserRequest {
|
||||||
|
id: String,
|
||||||
|
email: String,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
email_confirm: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
struct InviteRequest {
|
||||||
|
email: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
struct RecoverRequest {
|
||||||
|
email: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
struct UpdateUserRequest {
|
||||||
|
password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct User {
|
||||||
|
pub id: String,
|
||||||
|
pub email: String,
|
||||||
|
pub aud: String,
|
||||||
|
pub role: String,
|
||||||
|
pub created_at: String,
|
||||||
|
pub updated_at: String,
|
||||||
|
pub email_confirmed_at: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main Supabase client struct
|
||||||
|
pub struct SupabaseClient {
|
||||||
|
url: String,
|
||||||
|
service_role_key: String,
|
||||||
|
client: Client,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SupabaseClient {
|
||||||
|
// Initialize the client with env variables
|
||||||
|
pub fn new() -> Result<Self, env::VarError> {
|
||||||
|
dotenv().ok(); // Load .env file
|
||||||
|
|
||||||
|
let url = env::var("SUPABASE_URL")?;
|
||||||
|
let service_role_key = env::var("SUPABASE_SERVICE_ROLE_KEY")?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
url,
|
||||||
|
service_role_key,
|
||||||
|
client: Client::new(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Create a new user with a specific ID
|
||||||
|
pub async fn create_user(&self, id: Uuid, email: &str) -> Result<User, Error> {
|
||||||
|
let payload = CreateUserRequest {
|
||||||
|
id: id.to_string(),
|
||||||
|
email: email.to_string(),
|
||||||
|
email_confirm: Some(false), // Email unconfirmed initially
|
||||||
|
};
|
||||||
|
|
||||||
|
let response = self
|
||||||
|
.client
|
||||||
|
.post(format!("{}/auth/v1/admin/users", self.url))
|
||||||
|
.header("Authorization", format!("Bearer {}", self.service_role_key))
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("apikey", &self.service_role_key)
|
||||||
|
.json(&payload)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let user = response.json::<User>().await?;
|
||||||
|
Ok(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Send a verification email
|
||||||
|
pub async fn send_verification_email(&self, email: &str) -> Result<(), Error> {
|
||||||
|
let payload = InviteRequest {
|
||||||
|
email: email.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.client
|
||||||
|
.post(format!("{}/auth/v1/invite", self.url))
|
||||||
|
.header("Authorization", format!("Bearer {}", self.service_role_key))
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("apikey", &self.service_role_key)
|
||||||
|
.json(&payload)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3a. Trigger a password reset email (for user to set password)
|
||||||
|
pub async fn send_password_reset_email(&self, email: &str) -> Result<(), Error> {
|
||||||
|
let payload = RecoverRequest {
|
||||||
|
email: email.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.client
|
||||||
|
.post(format!("{}/auth/v1/recover", self.url))
|
||||||
|
.header("Authorization", format!("Bearer {}", self.service_role_key))
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("apikey", &self.service_role_key)
|
||||||
|
.json(&payload)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3b. Update user password (simulating user action with recovery token)
|
||||||
|
pub async fn update_user_password(&self, recovery_token: &str, password: &str) -> Result<(), Error> {
|
||||||
|
let payload = UpdateUserRequest {
|
||||||
|
password: password.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.client
|
||||||
|
.put(format!("{}/auth/v1/user", self.url))
|
||||||
|
.header("Authorization", format!("Bearer {}", recovery_token))
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("apikey", &self.service_role_key)
|
||||||
|
.json(&payload)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example usage in a main function (for testing)
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_supabase_client() {
|
||||||
|
let client = SupabaseClient::new().expect("Failed to initialize client");
|
||||||
|
|
||||||
|
// 1. Create a user
|
||||||
|
let user_id = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
|
||||||
|
let user = client.create_user(user_id, "newuser@example.com").await.unwrap();
|
||||||
|
println!("Created user: {:?}", user);
|
||||||
|
|
||||||
|
// 2. Send verification email
|
||||||
|
client.send_verification_email("newuser@example.com").await.unwrap();
|
||||||
|
println!("Verification email sent. Check Inbucket at http://localhost:54324");
|
||||||
|
|
||||||
|
// 3. Simulate password reset (manual token extraction needed from email)
|
||||||
|
client.send_password_reset_email("newuser@example.com").await.unwrap();
|
||||||
|
println!("Password reset email sent. Check Inbucket for recovery token");
|
||||||
|
|
||||||
|
// Normally, you'd extract the recovery token from the email and pass it here
|
||||||
|
// For testing, you'd need to manually get it from Inbucket
|
||||||
|
// client.update_user_password("<recovery-token>", "newsecurepassword123").await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod client;
|
Loading…
Reference in New Issue