✨ (auth): Añade CurrentUser y sistema de permisos
- Nuevo módulo `auth` que exporta `CurrentUser`, `CheckPermission` y `has_permission()`. - `Context` y `Page` exponen `current_user()` vía `Contextual`. - `HttpRequest` accede a extensiones de middleware con `extension<T>()`. - `Extension` incluye nuevo método `configure_middleware`. - `try_dispatch_actions` para despachar acciones con control del flujo.
This commit is contained in:
parent
3120fd9a6f
commit
0e96bcce64
22 changed files with 544 additions and 84 deletions
|
|
@ -45,9 +45,9 @@ pub(crate) fn add_action(action: ActionBox) {
|
|||
/// # Parámetros genéricos
|
||||
///
|
||||
/// - `A`: Tipo de acción que esperamos procesar. Debe implementar [`ActionDispatcher`].
|
||||
/// - `F`: Función asociada a cada acción, devuelve un valor de tipo `B`.
|
||||
/// - `F`: Función que se aplica para una acción dada.
|
||||
///
|
||||
/// # Ejemplo de uso
|
||||
/// # Ejemplo
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// pub(crate) fn dispatch(component: &mut C, cx: &mut Context) {
|
||||
|
|
@ -61,12 +61,47 @@ pub(crate) fn add_action(action: ActionBox) {
|
|||
/// );
|
||||
/// }
|
||||
/// ```
|
||||
pub fn dispatch_actions<A, B, F>(key: &ActionKey, f: F)
|
||||
pub fn dispatch_actions<A, F>(key: &ActionKey, f: F)
|
||||
where
|
||||
A: ActionDispatcher,
|
||||
F: FnMut(&A) -> B,
|
||||
F: FnMut(&A),
|
||||
{
|
||||
if let Some(list) = ACTIONS.read().get(key) {
|
||||
list.iter_map(f);
|
||||
list.for_each(f);
|
||||
}
|
||||
}
|
||||
|
||||
/// Despacha las funciones asociadas a una [`ActionKey`] con posible salida anticipada.
|
||||
///
|
||||
/// Funciona igual que [`dispatch_actions`], pero el *closure* puede devolver
|
||||
/// [`std::ops::ControlFlow::Continue`] para continuar ejecutando la siguiente acción; o
|
||||
/// [`std::ops::ControlFlow::Break`] para detener la iteración inmediatamente.
|
||||
///
|
||||
/// # Ejemplo
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// pub(crate) fn check(cx: &Context, key: &str) -> bool {
|
||||
/// let mut granted = false;
|
||||
/// try_dispatch_actions(
|
||||
/// &ActionKey::new(UniqueId::of::<Self>(), None, None),
|
||||
/// |action: &Self| {
|
||||
/// (action.f)(cx, key, &mut granted);
|
||||
/// if granted {
|
||||
/// std::ops::ControlFlow::Break(())
|
||||
/// } else {
|
||||
/// std::ops::ControlFlow::Continue(())
|
||||
/// }
|
||||
/// },
|
||||
/// );
|
||||
/// granted
|
||||
/// }
|
||||
/// ```
|
||||
pub fn try_dispatch_actions<A, F>(key: &ActionKey, f: F)
|
||||
where
|
||||
A: ActionDispatcher,
|
||||
F: FnMut(&A) -> std::ops::ControlFlow<()>,
|
||||
{
|
||||
if let Some(list) = ACTIONS.read().get(key) {
|
||||
list.try_for_each(f);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,17 +45,17 @@ impl ActionKey {
|
|||
/// Las acciones tienen que sobrescribir los métodos para el filtro que apliquen. Por defecto
|
||||
/// implementa un filtro nulo.
|
||||
pub trait ActionDispatcher: AnyInfo + Send + Sync {
|
||||
/// Identificador de tipo ([`UniqueId`]) del objeto referido. En este caso devuelve `None`.
|
||||
/// Devuelve el identificador de tipo ([`UniqueId`]) del objeto referido.
|
||||
fn referer_type_id(&self) -> Option<UniqueId> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Identificador del objeto referido. En este caso devuelve `None`.
|
||||
/// Devuelve el identificador del objeto referido.
|
||||
fn referer_id(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Funciones con pesos más bajos se aplican antes. En este caso siempre devuelve `0`.
|
||||
/// Devuelve el peso para definir el orden de ejecución.
|
||||
fn weight(&self) -> Weight {
|
||||
0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,24 +19,35 @@ impl ActionsList {
|
|||
list.sort_by_key(|a| a.weight());
|
||||
}
|
||||
|
||||
pub fn iter_map<A, B, F>(&self, mut f: F)
|
||||
pub fn for_each<A, F>(&self, mut f: F)
|
||||
where
|
||||
Self: Sized,
|
||||
A: ActionDispatcher,
|
||||
F: FnMut(&A) -> B,
|
||||
F: FnMut(&A),
|
||||
{
|
||||
let _: Vec<_> = self
|
||||
.0
|
||||
.read()
|
||||
.iter()
|
||||
.rev()
|
||||
.map(|a| {
|
||||
if let Some(action) = (**a).downcast_ref::<A>() {
|
||||
f(action);
|
||||
} else {
|
||||
trace::error!("Failed to downcast action of type {}", (**a).type_name());
|
||||
let list = self.0.read();
|
||||
for a in list.iter().rev() {
|
||||
if let Some(action) = (**a).downcast_ref::<A>() {
|
||||
f(action);
|
||||
} else {
|
||||
trace::error!("Failed to downcast action of type {}", (**a).type_name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_for_each<A, F>(&self, mut f: F)
|
||||
where
|
||||
A: ActionDispatcher,
|
||||
F: FnMut(&A) -> std::ops::ControlFlow<()>,
|
||||
{
|
||||
let list = self.0.read();
|
||||
for a in list.iter().rev() {
|
||||
if let Some(action) = (**a).downcast_ref::<A>() {
|
||||
if f(action).is_break() {
|
||||
break;
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
} else {
|
||||
trace::error!("Failed to downcast action of type {}", (**a).type_name());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue