pub trait Resource: Send + Sync {
Show 33 methods
// Required methods
fn resource_name(&self) -> &'static str;
fn base_path(&self) -> &'static str;
fn table_name(&self) -> &'static str;
fn clone_box(&self) -> Box<dyn Resource>;
// Provided methods
fn primary_key(&self) -> &'static str { ... }
fn menu_group(&self) -> Option<&'static str> { ... }
fn menu(&self) -> &'static str { ... }
fn allowed_roles(&self) -> Vec<String> { ... }
fn allowed_actions(&self) -> Option<Vec<MenuAction>> { ... }
fn custom_actions(&self) -> Vec<CustomAction> { ... }
fn permit_keys(&self) -> Vec<&'static str> { ... }
fn readonly_keys(&self) -> Vec<&'static str> { ... }
fn soft_delete(&self) -> bool { ... }
fn form_structure(&self) -> Option<Value> { ... }
fn filterable_fields(&self) -> Vec<FilterField> { ... }
fn list<'life0, 'life1, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn get<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait { ... }
fn create<'life0, 'life1, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
body: Value,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn update<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
id: &'life2 str,
body: Value,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait { ... }
fn delete<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait { ... }
fn form_fields(&self) -> Vec<Value> { ... }
fn list_page<'life0, 'life1, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn new_page<'life0, 'life1, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn edit_page<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait { ... }
fn view_page<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait { ... }
fn create_form<'life0, 'life1, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
form: HashMap<String, String>,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn update_form<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
id: &'life2 str,
form: HashMap<String, String>,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait { ... }
fn delete_form<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
id: &'life2 str,
csrf: Option<String>,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait { ... }
fn run_action<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
name: &'life2 str,
id: String,
body: Value,
csrf: Option<String>,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait { ... }
fn export<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
format: &'life2 str,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait { ... }
fn authorize(&self, ctx: &ReqCtx, action: Action<'_>) -> bool { ... }
fn filter_writable(
&self,
body: Value,
) -> Result<Map<String, Value>, ApiResponse> { ... }
fn generate_menu(&self) -> Option<MenuItem> { ... }
}Required Methods§
fn resource_name(&self) -> &'static str
fn base_path(&self) -> &'static str
Sourcefn table_name(&self) -> &'static str
fn table_name(&self) -> &'static str
Backing table (SQL) or collection (Mongo) name.
fn clone_box(&self) -> Box<dyn Resource>
Provided Methods§
fn primary_key(&self) -> &'static str
fn allowed_roles(&self) -> Vec<String>
fn allowed_actions(&self) -> Option<Vec<MenuAction>>
Sourcefn custom_actions(&self) -> Vec<CustomAction>
fn custom_actions(&self) -> Vec<CustomAction>
Extra id-scoped operations beyond CRUD, exposed at
POST /{base}/{id}/action/{name} and as buttons on the detail page.
Sourcefn permit_keys(&self) -> Vec<&'static str>
fn permit_keys(&self) -> Vec<&'static str>
Mass-assignment allow-list for create/update.
Sourcefn readonly_keys(&self) -> Vec<&'static str>
fn readonly_keys(&self) -> Vec<&'static str>
Columns that must never be client-set.
Sourcefn soft_delete(&self) -> bool
fn soft_delete(&self) -> bool
Whether delete should soft-delete (set deleted = true).
Sourcefn form_structure(&self) -> Option<Value>
fn form_structure(&self) -> Option<Value>
Custom form layout for create/edit pages. Return None to derive fields
from permit_keys(). Shape: { "groups": [{ "fields": [...] }] }.
Sourcefn filterable_fields(&self) -> Vec<FilterField>
fn filterable_fields(&self) -> Vec<FilterField>
Columns exposed as filters on the list page. Empty (the default) means no
filter bar is shown. Build entries with FilterField::text/select/boolean.
fn list<'life0, 'life1, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn create<'life0, 'life1, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
body: Value,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn update<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
id: &'life2 str,
body: Value,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn delete<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Sourcefn form_fields(&self) -> Vec<Value>
fn form_fields(&self) -> Vec<Value>
The form fields to render on create/edit. Derived from an explicit
form_structure() when present, otherwise from permit_keys().
fn list_page<'life0, 'life1, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn new_page<'life0, 'life1, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn edit_page<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn view_page<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Sourcefn create_form<'life0, 'life1, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
form: HashMap<String, String>,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn create_form<'life0, 'life1, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
form: HashMap<String, String>,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Handle a submitted create form; redirects to the list on success.
Sourcefn update_form<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
id: &'life2 str,
form: HashMap<String, String>,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn update_form<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
id: &'life2 str,
form: HashMap<String, String>,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Handle a submitted edit form; redirects to the item view on success.
Sourcefn delete_form<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
id: &'life2 str,
csrf: Option<String>,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn delete_form<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
id: &'life2 str,
csrf: Option<String>,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Handle a delete from the list UI; redirects back to the list. csrf is
the submitted hidden field, checked against the cookie before anything
is removed.
Sourcefn run_action<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
name: &'life2 str,
id: String,
body: Value,
csrf: Option<String>,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn run_action<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
name: &'life2 str,
id: String,
body: Value,
csrf: Option<String>,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Look up a custom action by name and run it (after auth + CSRF checks).
csrf is the submitted hidden field; the action button posts a form, so
it’s guarded like the other mutating form handlers.
Sourcefn export<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
format: &'life2 str,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn export<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ctx: &'life1 ReqCtx,
format: &'life2 str,
) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Export the resource’s rows as json or csv (used by ?download=).
Whether the principal in ctx may perform action on this resource.
Delegates to the authorization seam: always allowed when auth is not
configured; a registered Authorizer decides
per action; otherwise the principal must hold one of allowed_roles().
Sourcefn filter_writable(
&self,
body: Value,
) -> Result<Map<String, Value>, ApiResponse>
fn filter_writable( &self, body: Value, ) -> Result<Map<String, Value>, ApiResponse>
Apply the permit/readonly/primary-key rules to an incoming JSON body, returning the writable column map or a ready-made error response.
Trait Implementations§
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".