use async_trait::async_trait;
use reqwest::Client;
use log::{info, error, warn};
use serde::{Deserialize, Serialize};
use crate::error::FluxError;
use crate::traits::Flux;
use crate::key::{Key};
use crate::api::supabase::upsert::SupabaseUpsert;
use crate::api::supabase::select::SupabaseSelect;
use crate::api::traits::Fetch;
use crate::file::key_collection::KeyCollection;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SupabaseFlux {
#[serde(rename = "ref")]
pub ref_id: String,
pub token: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
struct TempSecret {
name: String,
value: String,
}
#[async_trait]
impl Flux for SupabaseFlux {
async fn initialize(&self) -> Result<(), FluxError> {
let list_request = SupabaseSelect {
ref_id: self.ref_id.clone(),
token: self.token.clone(),
};
let client = Client::new();
match list_request.fetch(&client).await {
Ok(response) => {
if response.status().is_success() {
let secrets: Vec<TempSecret> = response.json().await.map_err(|e| {
error!("Failed to deserialize Supabase secrets JSON: {}", e);
FluxError::FluxFailed("Failed to deserialize Supabase secrets JSON".to_string())
})?;
for secret in &secrets {
info!("Found secret - name: {}, value: {}", secret.name, secret.value);
}
Ok(())
} else {
error!("Failed to list Supabase secrets: {:?}", response.status());
Err(FluxError::FluxFailed("Failed to list Supabase secrets".to_string()))
}
}
Err(e) => {
error!("Failed to fetch existing secrets: {}", e);
Err(FluxError::FluxFailed(format!("Failed to fetch existing secrets: {}", e)))
}
}
}
async fn finalize(&self) -> Result<(), FluxError> {
Ok(())
}
async fn single(&self, key: &Key) -> Result<(), FluxError> {
let mut keys = KeyCollection::new();
keys.insert(key.clone());
self.batch(&keys).await
}
async fn batch(&self, keys: &KeyCollection) -> Result<(), FluxError> {
let client = Client::new();
let filtered_keys: Vec<Key> = keys.iter()
.filter_map(|key| {
if key.name().starts_with("SUPABASE_") {
warn!("Secret name '{}' is not allowed to start with 'SUPABASE_'. Skipping this key.", key.name());
None
} else {
Some(key.clone())
}
})
.collect();
if filtered_keys.is_empty() {
warn!("No valid keys provided for upserting secrets.");
return Err(FluxError::FluxFailed("No valid keys provided for upserting secrets.".to_string()));
}
let upsert_request = SupabaseUpsert {
ref_id: self.ref_id.clone(),
token: self.token.clone(),
keys: filtered_keys,
};
match upsert_request.fetch(&client).await {
Ok(response) => {
if response.status().is_success() {
info!("Successfully set Supabase secrets.");
Ok(())
} else {
let status = response.status();
let text = response.text().await.unwrap_or_default();
error!("Failed to set Supabase secrets: {} - {}", status, text);
Err(FluxError::FluxFailed("Failed to set Supabase secrets".to_string()))
}
}
Err(e) => {
error!("Failed to upsert secrets: {}", e);
Err(FluxError::FluxFailed(format!("Failed to upsert secrets: {}", e)))
}
}
}
async fn check(&self, _key: &Key) -> Result<Option<String>, FluxError> {
Ok(None)
}
async fn revert(&self, _key: &Key) -> Result<(), FluxError> {
Ok(())
}
async fn diff(&self, _key: &Key) -> Result<String, FluxError> {
Err(FluxError::NotImplementedError("diff".into()))
}
}