use toasty::Db;
use topcoat::{
context::Cx,
router::{Body, Router, RouterBuilderDiscoverExt},
};
use crate::{
Ability, Panel, RouterBuilderPanelExt, lens,
resource::{Resource, ResourceDef},
schema::{Field, Schema},
table::{Table, TextColumn},
};
#[derive(Debug, Clone, toasty::Model)]
pub(crate) struct Dummy {
#[key]
#[auto]
pub(crate) id: uuid::Uuid,
pub(crate) name: String,
}
pub(crate) fn dummy_table() -> Table<Dummy> {
Table::<Dummy>::new(TextColumn::new(lens!(Dummy.name)))
}
#[derive(Debug, Clone, toasty::Model)]
pub(crate) struct Subscriber {
#[key]
#[auto]
pub(crate) id: uuid::Uuid,
#[unique]
pub(crate) email: String,
}
pub(crate) fn panel_for<R: Resource>() -> Panel {
Panel::new("admin")
.resource::<R>()
.auth(crate::Auth::disabled())
}
pub(crate) fn panel_state(prefix: &str, auth: crate::Auth) -> super::state::PanelState {
super::state::PanelState {
prefix: prefix.to_string(),
nav_items: Vec::new(),
brand: None,
dark_mode: false,
shell_assets: None,
search: std::collections::HashMap::new(),
relations: std::collections::HashMap::new(),
children: std::collections::HashMap::new(),
mounts: std::sync::Arc::default(),
root_redirect: None,
auth,
login_hint: None,
uploads: None,
served_paths: Vec::new(),
urls: std::collections::HashMap::new(),
}
}
pub(crate) fn current_panel(state: super::state::PanelState) -> super::state::CurrentPanel {
super::state::CurrentPanel(std::sync::Arc::new(state))
}
pub(crate) fn mount_without_db(panel: Panel) -> topcoat::Result<Router> {
Ok(Router::builder().discover().panel(panel)?.build())
}
pub(crate) fn mount(db: Db, panel: Panel) -> topcoat::Result<Router> {
Ok(Router::builder()
.discover()
.app_context(db)
.panel(panel)?
.build())
}
pub(crate) fn refusal(mounted: topcoat::Result<Router>) -> Vec<crate::DeclarationError> {
let Err(error) = mounted else {
panic!("the panel must not mount");
};
error
.downcast_ref::<crate::MountError>()
.unwrap_or_else(|| panic!("a declaration mistake refuses the panel, got {error}"))
.errors()
.to_vec()
}
pub(crate) async fn response_html(response: http::Response<Body>) -> String {
String::from_utf8_lossy(
&http_body_util::BodyExt::collect(response.into_body())
.await
.unwrap()
.to_bytes(),
)
.to_string()
}
pub(crate) async fn seed_dummies(db: &mut Db, rows: usize, name: impl Fn(usize) -> String) {
let mut create = Dummy::create_many();
for i in 0..rows {
create = create.item(Dummy::create().name(name(i)));
}
create.exec(&mut *db).await.unwrap();
}
#[derive(Debug, toasty::Model, Clone)]
pub(crate) struct Tagged {
#[key]
#[auto]
pub(crate) id: uuid::Uuid,
pub(crate) name: String,
#[unique]
pub(crate) token: uuid::Uuid,
}
pub(crate) struct TaggedResource;
impl crate::resource::Resource for TaggedResource {
type Model = Tagged;
type Form = TaggedForm;
fn declare() -> ResourceDef<Self> {
ResourceDef::new()
.slug("tagged")
.policy(|_cx: &Cx, ability: Ability<'_, Tagged>| {
matches!(
ability,
Ability::ViewAny | Ability::View(_) | Ability::Create | Ability::Update(_)
)
})
.table(crate::table::Table::new(crate::table::TextColumn::new(
lens!(Tagged.name),
)))
.form(Schema::new((
Field::text(Tagged::fields().name()),
Field::text(Tagged::fields().token()).unique(),
)))
}
}
#[derive(crate::RecordForm)]
#[form(model = Tagged)]
pub(crate) struct TaggedForm {
pub(crate) name: String,
pub(crate) token: uuid::Uuid,
}