use topcoat::context::Cx;
use super::signed;
use crate::{table::ColumnChoice, topcoat_compat::href};
#[derive(Debug, Clone, toasty::Model)]
pub struct ColumnPreference {
#[key]
pub key: String,
#[index]
pub user_id: String,
pub panel: String,
pub resource: String,
#[column(type = text)]
pub columns: String,
}
fn preference_key(panel: &str, user_id: &str, slug: &str) -> String {
href::encode_query(&[
("panel".to_string(), panel),
("user".to_string(), user_id),
("resource".to_string(), slug),
])
}
pub(crate) async fn load_choice(cx: &Cx, slug: &str) -> ColumnChoice {
let Some(signed) = signed(cx) else {
return ColumnChoice::default();
};
let key = preference_key(&signed.realm.prefix, &signed.user.user_id(), slug);
let Ok(mut db) = crate::db::db(cx) else {
return ColumnChoice::default();
};
match ColumnPreference::filter(ColumnPreference::fields().key().eq(key))
.first()
.exec(&mut db)
.await
{
Ok(row) => row.map_or_else(ColumnChoice::default, |row| {
ColumnChoice::decode(&row.columns)
}),
Err(error) => {
tracing::warn!(resource = slug, error = %error, "column preference load failed");
ColumnChoice::default()
}
}
}
pub(crate) async fn save_choice(cx: &Cx, slug: &str, choice: &ColumnChoice) -> topcoat::Result<()> {
let Some(signed) = signed(cx) else {
return Err(topcoat::router::error::forbidden().into());
};
let user_id = signed.user.user_id();
let panel = signed.realm.prefix.clone();
let key = preference_key(&panel, &user_id, slug);
let mut db = crate::db::db(cx)?;
let mut tx = db.transaction().await.map_err(crate::error::unavailable)?;
ColumnPreference::filter(ColumnPreference::fields().key().eq(key.clone()))
.delete()
.exec(&mut tx)
.await
.map_err(crate::error::unavailable)?;
if !choice.is_default() {
toasty::create!(ColumnPreference {
key,
user_id,
panel,
resource: slug.to_string(),
columns: choice.encode(),
})
.exec(&mut tx)
.await
.map_err(crate::error::unavailable)?;
}
tx.commit().await.map_err(crate::error::unavailable)
}