💥 (admin): Exige un permiso propio en cada página
This commit is contained in:
parent
2299e63585
commit
f337119219
6 changed files with 31 additions and 79 deletions
|
|
@ -87,9 +87,8 @@ impl ActionBag {
|
|||
/// bag.add(AdminSection {
|
||||
/// key: "tools".to_owned(),
|
||||
/// path: "/admin/tools".to_owned(),
|
||||
/// title: Lc::n("Tools"),
|
||||
/// permission: None,
|
||||
/// weight: 60,
|
||||
/// title: Lc::n("Tools"),
|
||||
/// weight: 60,
|
||||
/// });
|
||||
/// }
|
||||
/// // En Extension::actions():
|
||||
|
|
@ -130,10 +129,18 @@ impl DeclareAdminSections {
|
|||
/// # Ejemplo
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use pagetop::locale::Lc;
|
||||
/// use pagetop::prelude::*;
|
||||
/// use pagetop_admin::action::{DeclareAdminPages, PageBag};
|
||||
/// use pagetop_admin::registry::{AdminPage, AdminPageKind};
|
||||
///
|
||||
/// struct ExportPermission;
|
||||
///
|
||||
/// impl Permission for ExportPermission {
|
||||
/// fn key(&self) -> CowStr {
|
||||
/// "tools:export".into()
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn declare_pages(bag: &mut PageBag) {
|
||||
/// bag.add(AdminPage {
|
||||
/// path: "/admin/tools/export".to_owned(),
|
||||
|
|
@ -141,7 +148,7 @@ impl DeclareAdminSections {
|
|||
/// title: Lc::n("Export"),
|
||||
/// description: Some(Lc::n("Export site data.")),
|
||||
/// weight: 0,
|
||||
/// permission: None,
|
||||
/// permission: &ExportPermission,
|
||||
/// kind: AdminPageKind::View,
|
||||
/// });
|
||||
/// }
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ fn render_sections(cx: &Context, candidates: &[&'static AdminSection]) -> Option
|
|||
let sections_with_pages: Vec<_> = candidates
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|section| section.is_visible(cx))
|
||||
.map(|section| {
|
||||
let pages: Vec<_> = reg
|
||||
.pages_for_section(§ion.key)
|
||||
|
|
@ -131,7 +130,7 @@ pub async fn config_form_get(request: HttpRequest) -> Result<Markup, ErrorPage>
|
|||
return Err(ErrorPage::NotFound(Some(request.clone())));
|
||||
};
|
||||
|
||||
require_permission(&request, page.permission_key())?;
|
||||
require_permission(&request, page.permission)?;
|
||||
|
||||
let title = page.title.clone();
|
||||
let mut form = ConfigForm::with_schema(schema.clone());
|
||||
|
|
@ -170,7 +169,7 @@ pub async fn config_form_post(
|
|||
return Err(ErrorPage::NotFound(Some(request.clone())));
|
||||
};
|
||||
|
||||
require_permission(&request, page.permission_key())?;
|
||||
require_permission(&request, page.permission)?;
|
||||
|
||||
let mut save_error = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ fn declare_pages(bag: &mut PageBag) {
|
|||
title: Lc::n("My App"),
|
||||
description: Some(Lc::n("Configure My App.")),
|
||||
weight: 0,
|
||||
permission: Some(&MyPermission::Config),
|
||||
permission: &MyPermission::Config,
|
||||
kind: AdminPageKind::View,
|
||||
});
|
||||
}
|
||||
|
|
@ -63,7 +63,7 @@ enum MyPermission {
|
|||
impl Permission for MyPermission {
|
||||
fn key(&self) -> CowStr {
|
||||
match self {
|
||||
Self::Config => "myapp.config".into(),
|
||||
Self::Config => "myapp:config".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,38 +14,12 @@ use crate::action::{
|
|||
};
|
||||
use crate::settings::SettingsSchema;
|
||||
|
||||
// **< AdminPermission >****************************************************************************
|
||||
|
||||
/// Permisos propios de `pagetop-admin`.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum AdminPermission {
|
||||
/// Acceso por defecto a una página de administración que no declara un permiso propio.
|
||||
Access,
|
||||
/// Acceso a la sección integrada "people".
|
||||
AccessPeople,
|
||||
/// Acceso a la sección integrada "structure".
|
||||
AccessStructure,
|
||||
/// Acceso a la sección integrada "config".
|
||||
AccessConfig,
|
||||
/// Acceso a la sección integrada "reports".
|
||||
AccessReports,
|
||||
}
|
||||
|
||||
impl Permission for AdminPermission {
|
||||
fn key(&self) -> CowStr {
|
||||
match self {
|
||||
Self::Access => "admin:access".into(),
|
||||
Self::AccessPeople => "admin.access_people".into(),
|
||||
Self::AccessStructure => "admin.access_structure".into(),
|
||||
Self::AccessConfig => "admin.access_config".into(),
|
||||
Self::AccessReports => "admin.access_reports".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **< Tipos del registro >*************************************************************************
|
||||
|
||||
/// Sección del panel de administración (agrupación en el sidebar).
|
||||
/// Sección del panel de administración (agrupación de páginas en el menú y en el *dashboard*).
|
||||
///
|
||||
/// Una sección no tiene permiso propio: se muestra a quien pueda acceder a alguna de sus páginas, y
|
||||
/// se oculta si no le queda ninguna.
|
||||
#[derive(Clone)]
|
||||
pub struct AdminSection {
|
||||
/// Identificador único de la sección (p. ej. `"config"`).
|
||||
|
|
@ -54,24 +28,10 @@ pub struct AdminSection {
|
|||
pub path: String,
|
||||
/// Título visible en el sidebar.
|
||||
pub title: Lc,
|
||||
/// Permiso requerido para ver la sección (`None` = siempre visible).
|
||||
pub permission: Option<PermissionRef>,
|
||||
/// Peso para ordenar en el sidebar (menor = antes).
|
||||
pub weight: i32,
|
||||
}
|
||||
|
||||
impl AdminSection {
|
||||
/// Devuelve `true` si el usuario actual puede ver esta sección.
|
||||
pub fn is_visible(&self, cx: &Context) -> bool {
|
||||
match self.permission {
|
||||
None => true,
|
||||
Some(permission) => cx
|
||||
.request()
|
||||
.is_some_and(|request| has_permission(request, permission)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Página del panel de administración.
|
||||
#[derive(Clone)]
|
||||
pub struct AdminPage {
|
||||
|
|
@ -85,22 +45,18 @@ pub struct AdminPage {
|
|||
pub description: Option<Lc>,
|
||||
/// Peso dentro de la sección (menor = antes).
|
||||
pub weight: i32,
|
||||
/// Permiso requerido para acceder (`None` = requiere [`AdminPermission::Access`]).
|
||||
pub permission: Option<PermissionRef>,
|
||||
/// Permiso requerido para acceder. Es obligatorio: cada página declara el suyo, y es también
|
||||
/// el que decide si su sección se muestra.
|
||||
pub permission: PermissionRef,
|
||||
/// Tipo de página y datos asociados.
|
||||
pub kind: AdminPageKind,
|
||||
}
|
||||
|
||||
impl AdminPage {
|
||||
/// Permiso efectivo: el declarado, o [`AdminPermission::Access`] si no se especificó ninguno.
|
||||
pub fn permission_key(&self) -> PermissionRef {
|
||||
self.permission.unwrap_or(&AdminPermission::Access)
|
||||
}
|
||||
|
||||
/// Devuelve `true` si el usuario actual puede acceder a esta página.
|
||||
pub fn is_accessible(&self, cx: &Context) -> bool {
|
||||
cx.request()
|
||||
.is_some_and(|request| has_permission(request, self.permission_key()))
|
||||
.is_some_and(|request| has_permission(request, self.permission))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -277,11 +233,9 @@ pub fn global() -> &'static AdminRegistry {
|
|||
pub fn can_access_admin(cx: &Context) -> bool {
|
||||
let reg = global();
|
||||
reg.ordered_sections().into_iter().any(|section| {
|
||||
section.is_visible(cx)
|
||||
&& reg
|
||||
.pages_for_section(§ion.key)
|
||||
.into_iter()
|
||||
.any(|page| page.is_accessible(cx))
|
||||
reg.pages_for_section(§ion.key)
|
||||
.into_iter()
|
||||
.any(|page| page.is_accessible(cx))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -306,9 +260,6 @@ pub fn admin_navbar(cx: &Context) -> Navbar {
|
|||
));
|
||||
|
||||
for section in reg.ordered_sections() {
|
||||
if !section.is_visible(cx) {
|
||||
continue;
|
||||
}
|
||||
let pages: Vec<_> = reg
|
||||
.pages_for_section(§ion.key)
|
||||
.into_iter()
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use pagetop::prelude::*;
|
|||
use crate::ADMIN_BASE_PATH;
|
||||
use crate::LOCALES_ADMIN;
|
||||
use crate::action::SectionBag;
|
||||
use crate::registry::{AdminPermission, AdminSection};
|
||||
use crate::registry::AdminSection;
|
||||
|
||||
/// Declara las secciones incorporadas del panel de administración.
|
||||
///
|
||||
|
|
@ -16,35 +16,30 @@ pub(crate) fn declare_default_sections(bag: &mut SectionBag) {
|
|||
key: "people".to_owned(),
|
||||
path: format!("{}/people", base),
|
||||
title: Lc::t("section-people", &LOCALES_ADMIN),
|
||||
permission: Some(&AdminPermission::AccessPeople),
|
||||
weight: 10,
|
||||
});
|
||||
bag.add(AdminSection {
|
||||
key: "structure".to_owned(),
|
||||
path: format!("{}/structure", base),
|
||||
title: Lc::t("section-structure", &LOCALES_ADMIN),
|
||||
permission: Some(&AdminPermission::AccessStructure),
|
||||
weight: 20,
|
||||
});
|
||||
bag.add(AdminSection {
|
||||
key: "config".to_owned(),
|
||||
path: format!("{}/config", base),
|
||||
title: Lc::t("section-config", &LOCALES_ADMIN),
|
||||
permission: Some(&AdminPermission::AccessConfig),
|
||||
weight: 30,
|
||||
});
|
||||
bag.add(AdminSection {
|
||||
key: "reports".to_owned(),
|
||||
path: format!("{}/reports", base),
|
||||
title: Lc::t("section-reports", &LOCALES_ADMIN),
|
||||
permission: Some(&AdminPermission::AccessReports),
|
||||
weight: 40,
|
||||
});
|
||||
bag.add(AdminSection {
|
||||
key: "help".to_owned(),
|
||||
path: format!("{}/help", base),
|
||||
title: Lc::t("section-help", &LOCALES_ADMIN),
|
||||
permission: None,
|
||||
weight: 50,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ fn declare_admin_pages(bag: &mut PageBag) {
|
|||
title: Lc::t("title-admin-users", &LOCALES_USER),
|
||||
description: Some(Lc::t("description-admin-users", &LOCALES_USER)),
|
||||
weight: 0,
|
||||
permission: Some(&permission::UserPermission::AdminUsers),
|
||||
permission: &permission::UserPermission::AdminUsers,
|
||||
kind: AdminPageKind::View,
|
||||
});
|
||||
bag.add(AdminPage {
|
||||
|
|
@ -164,7 +164,7 @@ fn declare_admin_pages(bag: &mut PageBag) {
|
|||
title: Lc::t("title-admin-roles", &LOCALES_USER),
|
||||
description: Some(Lc::t("description-admin-roles", &LOCALES_USER)),
|
||||
weight: 10,
|
||||
permission: Some(&permission::UserPermission::AdminRoles),
|
||||
permission: &permission::UserPermission::AdminRoles,
|
||||
kind: AdminPageKind::View,
|
||||
});
|
||||
bag.add(AdminPage {
|
||||
|
|
@ -173,7 +173,7 @@ fn declare_admin_pages(bag: &mut PageBag) {
|
|||
title: Lc::t("title-admin-permissions", &LOCALES_USER),
|
||||
description: Some(Lc::t("description-admin-permissions", &LOCALES_USER)),
|
||||
weight: 20,
|
||||
permission: Some(&permission::UserPermission::AdminPermissions),
|
||||
permission: &permission::UserPermission::AdminPermissions,
|
||||
kind: AdminPageKind::View,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue