Skip to main content

Resource

Trait Resource 

Source
pub trait Resource: Send + Sync {
Show 39 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 file_fields(&self) -> Vec<FileField> { ... } fn search_fields(&self) -> Vec<&'static str> { ... } fn list<'life0, 'life1, 'async_trait>( &'life0 self, ctx: &'life1 ReqCtx, ) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, Self: '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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: '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 'life0: 'async_trait, 'life1: 'async_trait, Self: '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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: '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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: '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 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait { ... } fn new_page<'life0, 'life1, 'async_trait>( &'life0 self, ctx: &'life1 ReqCtx, ) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, Self: '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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: '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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait { ... } fn attach_file<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, ctx: &'life1 ReqCtx, id: &'life2 str, field: &'life3 str, csrf: Option<String>, file: UploadedFile, ) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, Self: 'async_trait { ... } fn serve_file<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, ctx: &'life1 ReqCtx, id: &'life2 str, field: &'life3 str, ) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, Self: 'async_trait { ... } fn detach_file<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, ctx: &'life1 ReqCtx, id: &'life2 str, field: &'life3 str, csrf: Option<String>, ) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, Self: 'async_trait { ... } fn history_page<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, ctx: &'life1 ReqCtx, id: &'life2 str, ) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: '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 'life0: 'async_trait, 'life1: 'async_trait, Self: '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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: '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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: '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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: '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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: '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§

Source

fn resource_name(&self) -> &'static str

Source

fn base_path(&self) -> &'static str

Source

fn table_name(&self) -> &'static str

Backing table (SQL) or collection (Mongo) name.

Source

fn clone_box(&self) -> Box<dyn Resource>

Provided Methods§

Source

fn primary_key(&self) -> &'static str

Source

fn menu_group(&self) -> Option<&'static str>

Source

fn menu(&self) -> &'static str

Source

fn allowed_roles(&self) -> Vec<String>

Source

fn allowed_actions(&self) -> Option<Vec<MenuAction>>

Source

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.

Source

fn permit_keys(&self) -> Vec<&'static str>

Mass-assignment allow-list for create/update.

Source

fn readonly_keys(&self) -> Vec<&'static str>

Columns that must never be client-set.

Source

fn soft_delete(&self) -> bool

Whether delete should soft-delete (set deleted = true).

Source

fn form_structure(&self) -> Option<Value>

Custom form layout for create/edit pages. Return None to derive fields from permit_keys(). Shape: { "groups": [{ "fields": [...] }] }.

Source

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.

Source

fn file_fields(&self) -> Vec<FileField>

File attachments this resource accepts. Empty (the default) means no upload widgets are shown. Each field renders an <input type=file> on the detail page, backed by the attach/serve/detach routes. Requires an attachment backend (adminx-storage) to be registered; without one the widgets are hidden.

Source

fn search_fields(&self) -> Vec<&'static str>

Columns included in this resource’s full-text search document. Empty (the default) means the resource is not searchable — no search box, no indexing. When non-empty and a search backend (adminx-search) is registered, create/update keep the index in sync, delete removes the record, and the list page grows a ?q= search box.

Source

fn list<'life0, 'life1, 'async_trait>( &'life0 self, ctx: &'life1 ReqCtx, ) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait,

Source

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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Source

fn create<'life0, 'life1, 'async_trait>( &'life0 self, ctx: &'life1 ReqCtx, body: Value, ) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait,

Create. The body lives in crud::create so an overriding impl can delegate to it and keep the audit recording; see that module for why.

Source

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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Update. Body in crud::update.

Source

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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Delete. Body in crud::delete.

Source

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().

Source

fn list_page<'life0, 'life1, 'async_trait>( &'life0 self, ctx: &'life1 ReqCtx, ) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait,

Source

fn new_page<'life0, 'life1, 'async_trait>( &'life0 self, ctx: &'life1 ReqCtx, ) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait,

Source

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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Source

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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Source

fn attach_file<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, ctx: &'life1 ReqCtx, id: &'life2 str, field: &'life3 str, csrf: Option<String>, file: UploadedFile, ) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, Self: 'async_trait,

Store an uploaded file against this record under field. Called by the web adapter after it parses the multipart body; redirects back to the detail page on success. Gated on Update — attaching a file changes the record.

Source

fn serve_file<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, ctx: &'life1 ReqCtx, id: &'life2 str, field: &'life3 str, ) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, Self: 'async_trait,

Stream a stored attachment back. Gated on Read — seeing the file is a read of the record it belongs to. Returns the bytes with the stored content type and a download-friendly filename.

Source

fn detach_file<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, ctx: &'life1 ReqCtx, id: &'life2 str, field: &'life3 str, csrf: Option<String>, ) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, Self: 'async_trait,

Remove one field’s attachment. Gated on Update; redirects back to the detail page.

Source

fn history_page<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, ctx: &'life1 ReqCtx, id: &'life2 str, ) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

The recorded history of one record. Reads through the audit seam, so with no auditor registered it renders an empty log rather than 404 — the route exists either way and the page explains itself.

Source

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 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait,

Handle a submitted create form; redirects to the list on success.

Source

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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Handle a submitted edit form; redirects to the item view on success.

Source

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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: '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.

Source

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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: '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.

Source

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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Export the resource’s rows as json or csv (used by ?download=).

Source

fn authorize(&self, ctx: &ReqCtx, action: Action<'_>) -> bool

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().

Source

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.

Source

fn generate_menu(&self) -> Option<MenuItem>

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementations on Foreign Types§

Source§

impl Resource for AuditVersionResource

Source§

fn permit_keys(&self) -> Vec<&'static str>

Nothing is writable. This also means filter_writable can never admit a column, so even if a mutating override were removed the defaults would reject the body rather than insert a forged entry.

Source§

fn resource_name(&self) -> &'static str

Source§

fn base_path(&self) -> &'static str

Source§

fn table_name(&self) -> &'static str

Source§

fn clone_box(&self) -> Box<dyn Resource>

Source§

fn menu(&self) -> &'static str

Source§

fn filterable_fields(&self) -> Vec<FilterField>

Source§

fn create<'life0, 'life1, 'async_trait>( &'life0 self, _ctx: &'life1 ReqCtx, _body: Value, ) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, AuditVersionResource: 'async_trait,

Source§

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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, AuditVersionResource: 'async_trait,

Source§

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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, AuditVersionResource: 'async_trait,

Source§

fn new_page<'life0, 'life1, 'async_trait>( &'life0 self, ctx: &'life1 ReqCtx, ) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, AuditVersionResource: 'async_trait,

Source§

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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, AuditVersionResource: 'async_trait,

Source§

impl Resource for PermissionResource

Source§

fn resource_name(&self) -> &'static str

Source§

fn base_path(&self) -> &'static str

Source§

fn table_name(&self) -> &'static str

Source§

fn clone_box(&self) -> Box<dyn Resource>

Source§

fn permit_keys(&self) -> Vec<&'static str>

Source§

fn menu(&self) -> &'static str

Source§

fn create<'life0, 'life1, 'async_trait>( &'life0 self, ctx: &'life1 ReqCtx, body: Value, ) -> Pin<Box<dyn Future<Output = ApiResponse> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, PermissionResource: 'async_trait,

Source§

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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, PermissionResource: 'async_trait,

Source§

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 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, PermissionResource: 'async_trait,

Source§

impl Resource for RoleResource

Source§

fn resource_name(&self) -> &'static str

Source§

fn base_path(&self) -> &'static str

Source§

fn table_name(&self) -> &'static str

Source§

fn clone_box(&self) -> Box<dyn Resource>

Source§

fn permit_keys(&self) -> Vec<&'static str>

Source§

fn menu(&self) -> &'static str

Implementors§