♻️ Importa PageTop usando el prelude

This commit is contained in:
Manuel Cillero 2026-09-20 18:33:37 +02:00
parent 8651b91ab2
commit 404739a3fd
31 changed files with 96 additions and 112 deletions

1
Cargo.lock generated
View file

@ -1875,7 +1875,6 @@ dependencies = [
name = "pagetop-menu" name = "pagetop-menu"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"chrono",
"pagetop", "pagetop",
"pagetop-seaorm", "pagetop-seaorm",
"serde", "serde",

View file

@ -1,4 +1,3 @@
use pagetop::base::component::breadcrumb;
use pagetop::prelude::*; use pagetop::prelude::*;
use crate::LOCALES_ADMIN; use crate::LOCALES_ADMIN;

View file

@ -1,7 +1,6 @@
use pagetop::prelude::*;
use pagetop_seaorm::db::*; use pagetop_seaorm::db::*;
use pagetop::datetime::NaiveDateTime;
/// Entidad SeaORM para la tabla `settings`. /// Entidad SeaORM para la tabla `settings`.
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "settings")] #[sea_orm(table_name = "settings")]
@ -14,7 +13,7 @@ pub struct Model {
pub updated_by: Option<i32>, pub updated_by: Option<i32>,
} }
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] #[derive(Clone, Copy, Debug, DeriveRelation, EnumIter)]
pub enum Relation {} pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {} impl ActiveModelBehavior for ActiveModel {}

View file

@ -7,7 +7,7 @@
//! # Atributos estáticos en `html!` //! # Atributos estáticos en `html!`
//! //!
//! Para valores conocidos en tiempo de compilación, los atributos `hx-*` pueden escribirse //! Para valores conocidos en tiempo de compilación, los atributos `hx-*` pueden escribirse
//! directamente en la macro `html!` sin necesidad de [`Props`](pagetop::html::Props): //! directamente en la macro `html!` sin necesidad de [`Props`]:
//! //!
//! ```rust,no_run //! ```rust,no_run
//! use pagetop::prelude::*; //! use pagetop::prelude::*;
@ -17,10 +17,10 @@
//! }; //! };
//! ``` //! ```
//! //!
//! # Atributos dinámicos con [`Props`](pagetop::html::Props) //! # Atributos dinámicos con [`Props`]
//! //!
//! Cuando los valores se construyen en tiempo de ejecución o se inyectan desde una extensión, //! Cuando los valores se construyen en tiempo de ejecución o se inyectan desde una extensión,
//! puedes usar [`Props`](pagetop::html::Props) combinado con las constantes de este módulo: //! puedes usar [`Props`] combinado con las constantes de este módulo:
//! //!
//! ```rust,no_run //! ```rust,no_run
//! # use pagetop::prelude::*; //! # use pagetop::prelude::*;

View file

@ -14,6 +14,5 @@ authors.workspace = true
[dependencies] [dependencies]
pagetop.workspace = true pagetop.workspace = true
pagetop-seaorm.workspace = true pagetop-seaorm.workspace = true
chrono.workspace = true
serde.workspace = true serde.workspace = true
thiserror.workspace = true thiserror.workspace = true

View file

@ -1,4 +1,3 @@
use pagetop::base::component::breadcrumb;
use pagetop::prelude::*; use pagetop::prelude::*;
use crate::tree::{MenuKey, MenuNode, TreeOptions, build_tree, try_resolve_menu_url}; use crate::tree::{MenuKey, MenuNode, TreeOptions, build_tree, try_resolve_menu_url};

View file

@ -1,7 +1,6 @@
use pagetop::prelude::*;
use pagetop_seaorm::db::*; use pagetop_seaorm::db::*;
use chrono::NaiveDateTime;
#[derive(Clone, Debug, DeriveEntityModel, PartialEq)] #[derive(Clone, Debug, DeriveEntityModel, PartialEq)]
#[sea_orm(table_name = "menus")] #[sea_orm(table_name = "menus")]
pub struct Model { pub struct Model {

View file

@ -1,7 +1,6 @@
use pagetop::prelude::*;
use pagetop_seaorm::db::*; use pagetop_seaorm::db::*;
use chrono::NaiveDateTime;
#[derive(Clone, Debug, DeriveEntityModel, PartialEq)] #[derive(Clone, Debug, DeriveEntityModel, PartialEq)]
#[sea_orm(table_name = "menu_items")] #[sea_orm(table_name = "menu_items")]
pub struct Model { pub struct Model {

View file

@ -1,8 +1,6 @@
//! Operaciones de base de datos para menús e ítems de menú. //! Operaciones de base de datos para menús e ítems de menú.
use chrono::Utc; use pagetop::prelude::*;
use pagetop::locale::Locale;
use pagetop_seaorm::db::{ use pagetop_seaorm::db::{
ActiveModelTrait, ActiveValue::NotSet, ColumnTrait, EntityTrait, QueryFilter, Set, dbconn, ActiveModelTrait, ActiveValue::NotSet, ColumnTrait, EntityTrait, QueryFilter, Set, dbconn,
}; };

View file

@ -2,7 +2,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use pagetop::locale::{Locale, RequestLocale};
use pagetop::prelude::*; use pagetop::prelude::*;
use crate::cache::FlatMenu; use crate::cache::FlatMenu;

View file

@ -49,7 +49,7 @@
//! pub name: String, //! pub name: String,
//! } //! }
//! //!
//! #[derive(Clone, Copy, Debug, EnumIter, DeriveRelation)] //! #[derive(Clone, Copy, Debug, DeriveRelation, EnumIter)]
//! pub enum Relation {} //! pub enum Relation {}
//! //!
//! // `DeriveEntityModel` genera también `ActiveModel`, `Entity`, `Column` y `PrimaryKey`. //! // `DeriveEntityModel` genera también `ActiveModel`, `Entity`, `Column` y `PrimaryKey`.
@ -468,7 +468,7 @@ impl<T> Paginated<T> {
/// pub email: String, /// pub email: String,
/// } /// }
/// ///
/// #[derive(Clone, Copy, Debug, EnumIter, DeriveRelation)] /// #[derive(Clone, Copy, Debug, DeriveRelation, EnumIter)]
/// pub enum Relation {} /// pub enum Relation {}
/// ///
/// impl ActiveModelBehavior for ActiveModel {} /// impl ActiveModelBehavior for ActiveModel {}

View file

@ -4,7 +4,7 @@ use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use std::time::SystemTime; use std::time::SystemTime;
use pagetop::trace::info; use pagetop::prelude::*;
use sea_orm::sea_query::{ use sea_orm::sea_query::{
self, Alias, Expr, ExprTrait, ForeignKey, IntoIden, Order, Query, SelectStatement, SimpleExpr, self, Alias, Expr, ExprTrait, ForeignKey, IntoIden, Order, Query, SelectStatement, SimpleExpr,
@ -182,10 +182,10 @@ pub trait MigratorTrait: Send {
{ {
Self::install(db).await?; Self::install(db).await?;
info!("Checking migration status"); trace::info!("Checking migration status");
for Migration { migration, status } in Self::get_migration_with_status(db).await? { for Migration { migration, status } in Self::get_migration_with_status(db).await? {
info!("Migration '{}'... {}", migration.name(), status); trace::info!("Migration '{}'... {}", migration.name(), status);
} }
Ok(()) Ok(())
@ -284,34 +284,35 @@ where
// Temporarily disable the foreign key check // Temporarily disable the foreign key check
if db_backend == DbBackend::Sqlite { if db_backend == DbBackend::Sqlite {
info!("Disabling foreign key check"); trace::info!("Disabling foreign key check");
db.execute(Statement::from_string( db.execute(Statement::from_string(
db_backend, db_backend,
"PRAGMA foreign_keys = OFF".to_owned(), "PRAGMA foreign_keys = OFF".to_owned(),
)) ))
.await?; .await?;
info!("Foreign key check disabled"); trace::info!("Foreign key check disabled");
} }
// Drop all foreign keys // Drop all foreign keys
if db_backend == DbBackend::MySql { if db_backend == DbBackend::MySql {
info!("Dropping all foreign keys"); trace::info!("Dropping all foreign keys");
let stmt = query_mysql_foreign_keys(db); let stmt = query_mysql_foreign_keys(db);
let rows = db.query_all(db_backend.build(&stmt)).await?; let rows = db.query_all(db_backend.build(&stmt)).await?;
for row in rows.into_iter() { for row in rows.into_iter() {
let constraint_name: String = row.try_get("", "CONSTRAINT_NAME")?; let constraint_name: String = row.try_get("", "CONSTRAINT_NAME")?;
let table_name: String = row.try_get("", "TABLE_NAME")?; let table_name: String = row.try_get("", "TABLE_NAME")?;
info!( trace::info!(
"Dropping foreign key '{}' from table '{}'", "Dropping foreign key '{}' from table '{}'",
constraint_name, table_name constraint_name,
table_name
); );
let mut stmt = ForeignKey::drop(); let mut stmt = ForeignKey::drop();
stmt.table(Alias::new(table_name.as_str())) stmt.table(Alias::new(table_name.as_str()))
.name(constraint_name.as_str()); .name(constraint_name.as_str());
db.execute(db_backend.build(&stmt)).await?; db.execute(db_backend.build(&stmt)).await?;
info!("Foreign key '{}' has been dropped", constraint_name); trace::info!("Foreign key '{}' has been dropped", constraint_name);
} }
info!("All foreign keys dropped"); trace::info!("All foreign keys dropped");
} }
// Drop all tables // Drop all tables
@ -319,39 +320,39 @@ where
let rows = db.query_all(db_backend.build(&stmt)).await?; let rows = db.query_all(db_backend.build(&stmt)).await?;
for row in rows.into_iter() { for row in rows.into_iter() {
let table_name: String = row.try_get("", "table_name")?; let table_name: String = row.try_get("", "table_name")?;
info!("Dropping table '{}'", table_name); trace::info!("Dropping table '{}'", table_name);
let mut stmt = Table::drop(); let mut stmt = Table::drop();
stmt.table(Alias::new(table_name.as_str())) stmt.table(Alias::new(table_name.as_str()))
.if_exists() .if_exists()
.cascade(); .cascade();
db.execute(db_backend.build(&stmt)).await?; db.execute(db_backend.build(&stmt)).await?;
info!("Table '{}' has been dropped", table_name); trace::info!("Table '{}' has been dropped", table_name);
} }
// Drop all types // Drop all types
if db_backend == DbBackend::Postgres { if db_backend == DbBackend::Postgres {
info!("Dropping all types"); trace::info!("Dropping all types");
let stmt = query_pg_types(db); let stmt = query_pg_types(db);
let rows = db.query_all(db_backend.build(&stmt)).await?; let rows = db.query_all(db_backend.build(&stmt)).await?;
for row in rows { for row in rows {
let type_name: String = row.try_get("", "typname")?; let type_name: String = row.try_get("", "typname")?;
info!("Dropping type '{}'", type_name); trace::info!("Dropping type '{}'", type_name);
let mut stmt = Type::drop(); let mut stmt = Type::drop();
stmt.name(Alias::new(&type_name)); stmt.name(Alias::new(&type_name));
db.execute(db_backend.build(&stmt)).await?; db.execute(db_backend.build(&stmt)).await?;
info!("Type '{}' has been dropped", type_name); trace::info!("Type '{}' has been dropped", type_name);
} }
} }
// Restore the foreign key check // Restore the foreign key check
if db_backend == DbBackend::Sqlite { if db_backend == DbBackend::Sqlite {
info!("Restoring foreign key check"); trace::info!("Restoring foreign key check");
db.execute(Statement::from_string( db.execute(Statement::from_string(
db_backend, db_backend,
"PRAGMA foreign_keys = ON".to_owned(), "PRAGMA foreign_keys = ON".to_owned(),
)) ))
.await?; .await?;
info!("Foreign key check restored"); trace::info!("Foreign key check restored");
} }
// Reapply all migrations // Reapply all migrations
@ -367,15 +368,15 @@ where
M::install(db).await?; M::install(db).await?;
/* /*
if let Some(steps) = steps { if let Some(steps) = steps {
info!("Applying {} pending migrations", steps); trace::info!("Applying {} pending migrations", steps);
} else { } else {
info!("Applying all pending migrations"); trace::info!("Applying all pending migrations");
} }
*/ */
let migrations = M::get_pending_migrations(db).await?.into_iter(); let migrations = M::get_pending_migrations(db).await?.into_iter();
/* /*
if migrations.len() == 0 { if migrations.len() == 0 {
info!("No pending migrations"); trace::info!("No pending migrations");
} }
*/ */
for Migration { migration, .. } in migrations { for Migration { migration, .. } in migrations {
@ -385,9 +386,9 @@ where
} }
*steps -= 1; *steps -= 1;
} }
info!("Applying migration '{}'", migration.name()); trace::info!("Applying migration '{}'", migration.name());
migration.up(manager).await?; migration.up(manager).await?;
info!("Migration '{}' has been applied", migration.name()); trace::info!("Migration '{}' has been applied", migration.name());
let now = SystemTime::now() let now = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH) .duration_since(SystemTime::UNIX_EPOCH)
.expect("SystemTime before UNIX EPOCH!"); .expect("SystemTime before UNIX EPOCH!");
@ -412,14 +413,14 @@ where
M::install(db).await?; M::install(db).await?;
if let Some(steps) = steps { if let Some(steps) = steps {
info!("Rolling back {} applied migrations", steps); trace::info!("Rolling back {} applied migrations", steps);
} else { } else {
info!("Rolling back all applied migrations"); trace::info!("Rolling back all applied migrations");
} }
let migrations = M::get_applied_migrations(db).await?.into_iter().rev(); let migrations = M::get_applied_migrations(db).await?.into_iter().rev();
if migrations.len() == 0 { if migrations.len() == 0 {
info!("No applied migrations"); trace::info!("No applied migrations");
} }
for Migration { migration, .. } in migrations { for Migration { migration, .. } in migrations {
if let Some(steps) = steps.as_mut() { if let Some(steps) = steps.as_mut() {
@ -428,9 +429,9 @@ where
} }
*steps -= 1; *steps -= 1;
} }
info!("Rolling back migration '{}'", migration.name()); trace::info!("Rolling back migration '{}'", migration.name());
migration.down(manager).await?; migration.down(manager).await?;
info!("Migration '{}' has been rollbacked", migration.name()); trace::info!("Migration '{}' has been rollbacked", migration.name());
seaql_migrations::Entity::delete_many() seaql_migrations::Entity::delete_many()
.filter(Expr::col(seaql_migrations::Column::Version).eq(migration.name())) .filter(Expr::col(seaql_migrations::Column::Version).eq(migration.name()))
.table_name(M::migration_table_name()) .table_name(M::migration_table_name())

View file

@ -1,6 +1,6 @@
use sea_orm::entity::prelude::*; use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] #[derive(Clone, Debug, DeriveEntityModel, Eq, PartialEq)]
// One should override the name of migration table via `MigratorTrait::migration_table_name` method // One should override the name of migration table via `MigratorTrait::migration_table_name` method
#[sea_orm(table_name = "seaql_migrations")] #[sea_orm(table_name = "seaql_migrations")]
pub struct Model { pub struct Model {
@ -9,7 +9,7 @@ pub struct Model {
pub applied_at: i64, pub applied_at: i64,
} }
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] #[derive(Clone, Copy, Debug, DeriveRelation, EnumIter)]
pub enum Relation {} pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {} impl ActiveModelBehavior for ActiveModel {}

View file

@ -2,7 +2,7 @@
use std::collections::HashSet; use std::collections::HashSet;
use pagetop::auth::PermissionRef; use pagetop::prelude::*;
// **< UserStatus >********************************************************************************* // **< UserStatus >*********************************************************************************
@ -56,9 +56,9 @@ impl PermissionSet {
/// Datos ricos del usuario autenticado inyectados por el middleware de sesión. /// Datos ricos del usuario autenticado inyectados por el middleware de sesión.
/// ///
/// Se almacena en las extensiones de la petición HTTP durante la fase de middleware y se /// Se almacena en las extensiones de la petición HTTP durante la fase de middleware y se accede
/// accede desde los handlers o desde handlers de [`CheckPermission`](pagetop::auth::CheckPermission) /// desde los handlers o desde handlers de [`CheckPermission`] mediante
/// mediante [`HttpRequest::extension::<Account>()`](pagetop::web::HttpRequest::extension). /// [`HttpRequest::extension::<Account>()`](pagetop::web::HttpRequest::extension).
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Account { pub struct Account {
pub id: i32, pub id: i32,

View file

@ -1,7 +1,6 @@
//! Lógica de autenticación: login, logout, registro, semilla inicial. //! Lógica de autenticación: login, logout, registro, semilla inicial.
use pagetop::datetime::{Duration, NaiveDateTime, Utc}; use pagetop::prelude::*;
use pagetop_seaorm::db::{ use pagetop_seaorm::db::{
ActiveModelTrait, ActiveValue, ColumnTrait, Condition, EntityTrait, PaginatorTrait, ActiveModelTrait, ActiveValue, ColumnTrait, Condition, EntityTrait, PaginatorTrait,
QueryFilter, Set, dbconn, QueryFilter, Set, dbconn,

View file

@ -1,8 +1,6 @@
//! Tabla de roles: cabeceras ordenables y filas con acciones. //! Tabla de roles: cabeceras ordenables y filas con acciones.
use pagetop::prelude::*; use pagetop::prelude::*;
use pagetop::base::component::table::{Column, Row};
use pagetop_htmx::hx; use pagetop_htmx::hx;
use pagetop_htmx::hx_table::sort_link; use pagetop_htmx::hx_table::sort_link;
@ -93,7 +91,7 @@ impl Component for RoleTable {
}; };
table.alter_row( table.alter_row(
Row::new() table::Row::new()
.with_cell(role.machine_name.as_str()) .with_cell(role.machine_name.as_str())
.with_cell(label_cell(role, &waypoint)) .with_cell(label_cell(role, &waypoint))
.with_cell(Html::with(move |_cx| { .with_cell(Html::with(move |_cx| {
@ -188,7 +186,12 @@ impl RoleTable {
// Construye la cabecera ordenable de una columna: el enlace ya funciona sin HTMX (navega con // Construye la cabecera ordenable de una columna: el enlace ya funciona sin HTMX (navega con
// una petición normal); `pagetop_htmx::hx_table::sort_link()` añade aparte los atributos `hx-*` // una petición normal); `pagetop_htmx::hx_table::sort_link()` añade aparte los atributos `hx-*`
// para que la tabla se actualice sin recargar la página cuando la extensión esté disponible. // para que la tabla se actualice sin recargar la página cuando la extensión esté disponible.
fn sort_column(&self, cx: &Context, field: RoleSortField, label_key: &'static str) -> Column { fn sort_column(
&self,
cx: &Context,
field: RoleSortField,
label_key: &'static str,
) -> table::Column {
let is_active = *self.sort() == field; let is_active = *self.sort() == field;
let active = is_active.then_some(*self.dir()); let active = is_active.then_some(*self.dir());
let next_dir = SortDir::next_for(active); let next_dir = SortDir::next_for(active);
@ -197,7 +200,7 @@ impl RoleTable {
.alter_param("sort", field.as_str()) .alter_param("sort", field.as_str())
.alter_param("dir", next_dir); .alter_param("dir", next_dir);
Column::new(Lc::t(label_key, &LOCALES_USER)).with_sort(sort_link( table::Column::new(Lc::t(label_key, &LOCALES_USER)).with_sort(sort_link(
route, route,
"#role-table-wrapper", "#role-table-wrapper",
active, active,

View file

@ -1,8 +1,6 @@
//! Tabla de usuarios: cabeceras ordenables, filas y paginación embebida. //! Tabla de usuarios: cabeceras ordenables, filas y paginación embebida.
use pagetop::prelude::*; use pagetop::prelude::*;
use pagetop::base::component::table::{Column, Row};
use pagetop_htmx::hx; use pagetop_htmx::hx;
use pagetop_htmx::hx_table::sort_link; use pagetop_htmx::hx_table::sort_link;
@ -75,7 +73,7 @@ impl Component for UserTable {
let status = user.status; let status = user.status;
table.alter_row( table.alter_row(
Row::new() table::Row::new()
.with_cell(username_cell(user, &waypoint)) .with_cell(username_cell(user, &waypoint))
.with_cell(user.email.as_str()) .with_cell(user.email.as_str())
.with_cell(user.display_name.as_deref().unwrap_or("-")) .with_cell(user.display_name.as_deref().unwrap_or("-"))
@ -163,7 +161,12 @@ impl UserTable {
// Construye la cabecera ordenable de una columna: el enlace ya funciona sin HTMX (navega con // Construye la cabecera ordenable de una columna: el enlace ya funciona sin HTMX (navega con
// una petición normal); `pagetop_htmx::hx_table::sort_link()` añade aparte los atributos `hx-*` // una petición normal); `pagetop_htmx::hx_table::sort_link()` añade aparte los atributos `hx-*`
// para que la tabla se actualice sin recargar la página cuando la extensión esté disponible. // para que la tabla se actualice sin recargar la página cuando la extensión esté disponible.
fn sort_column(&self, cx: &Context, field: UserSortField, label_key: &'static str) -> Column { fn sort_column(
&self,
cx: &Context,
field: UserSortField,
label_key: &'static str,
) -> table::Column {
let is_active = *self.sort() == field; let is_active = *self.sort() == field;
let active = is_active.then_some(*self.dir()); let active = is_active.then_some(*self.dir());
let next_dir = SortDir::next_for(active); let next_dir = SortDir::next_for(active);
@ -176,7 +179,7 @@ impl UserTable {
.alter_param("sort", field.as_str()) .alter_param("sort", field.as_str())
.alter_param("dir", next_dir); .alter_param("dir", next_dir);
Column::new(Lc::t(label_key, &LOCALES_USER)).with_sort(sort_link( table::Column::new(Lc::t(label_key, &LOCALES_USER)).with_sort(sort_link(
route, route,
"#user-table-wrapper", "#user-table-wrapper",
active, active,

View file

@ -4,8 +4,7 @@
//! `Extension::initialize()`, después de `auth::seed_initial_data()`. Si el rol //! `Extension::initialize()`, después de `auth::seed_initial_data()`. Si el rol
//! `demo_role_01` ya existe, la siembra se omite para no duplicar datos en reinicios. //! `demo_role_01` ya existe, la siembra se omite para no duplicar datos en reinicios.
use pagetop::datetime::Utc; use pagetop::prelude::*;
use pagetop_seaorm::db::{ActiveValue, ColumnTrait, EntityTrait, QueryFilter, Set, dbconn}; use pagetop_seaorm::db::{ActiveValue, ColumnTrait, EntityTrait, QueryFilter, Set, dbconn};
use crate::account::UserStatus; use crate::account::UserStatus;

View file

@ -1,7 +1,6 @@
use pagetop::prelude::*;
use pagetop_seaorm::db::*; use pagetop_seaorm::db::*;
use pagetop::datetime::NaiveDateTime;
#[derive(Clone, Debug, DeriveEntityModel, PartialEq)] #[derive(Clone, Debug, DeriveEntityModel, PartialEq)]
#[sea_orm(table_name = "roles")] #[sea_orm(table_name = "roles")]
pub struct Model { pub struct Model {

View file

@ -1,7 +1,6 @@
use pagetop::prelude::*;
use pagetop_seaorm::db::*; use pagetop_seaorm::db::*;
use pagetop::datetime::NaiveDateTime;
#[derive(Clone, Debug, DeriveEntityModel, PartialEq)] #[derive(Clone, Debug, DeriveEntityModel, PartialEq)]
#[sea_orm(table_name = "role_permissions")] #[sea_orm(table_name = "role_permissions")]
pub struct Model { pub struct Model {

View file

@ -1,7 +1,6 @@
use pagetop::prelude::*;
use pagetop_seaorm::db::*; use pagetop_seaorm::db::*;
use pagetop::datetime::NaiveDateTime;
#[derive(Clone, Debug, DeriveEntityModel, PartialEq)] #[derive(Clone, Debug, DeriveEntityModel, PartialEq)]
#[sea_orm(table_name = "sessions")] #[sea_orm(table_name = "sessions")]
pub struct Model { pub struct Model {

View file

@ -1,7 +1,6 @@
use pagetop::prelude::*;
use pagetop_seaorm::db::*; use pagetop_seaorm::db::*;
use pagetop::datetime::NaiveDateTime;
#[derive(Clone, Debug, DeriveEntityModel, PartialEq)] #[derive(Clone, Debug, DeriveEntityModel, PartialEq)]
#[sea_orm(table_name = "users")] #[sea_orm(table_name = "users")]
pub struct Model { pub struct Model {

View file

@ -1,7 +1,6 @@
use pagetop::prelude::*;
use pagetop_seaorm::db::*; use pagetop_seaorm::db::*;
use pagetop::datetime::NaiveDateTime;
#[derive(Clone, Debug, DeriveEntityModel, PartialEq)] #[derive(Clone, Debug, DeriveEntityModel, PartialEq)]
#[sea_orm(table_name = "user_tokens")] #[sea_orm(table_name = "user_tokens")]
pub struct Model { pub struct Model {

View file

@ -1,6 +1,5 @@
//! Handler HTTP para el perfil del propio usuario autenticado. //! Handler HTTP para el perfil del propio usuario autenticado.
use pagetop::base::component::table::Row;
use pagetop::prelude::*; use pagetop::prelude::*;
use crate::account::UserStatus; use crate::account::UserStatus;
@ -47,32 +46,32 @@ async fn profile_details(user: &user::Model, status: UserStatus, cx: &mut Contex
let mut table = Table::new() let mut table = Table::new()
.with_prop(PropsOp::add_classes("user-admin-table")) .with_prop(PropsOp::add_classes("user-admin-table"))
.with_row( .with_row(
Row::new() table::Row::new()
.with_cell(Lc::t("field-username-admin", &LOCALES_USER)) .with_cell(Lc::t("field-username-admin", &LOCALES_USER))
.with_cell(user.username.as_str()), .with_cell(user.username.as_str()),
) )
.with_row( .with_row(
Row::new() table::Row::new()
.with_cell(Lc::t("field-email", &LOCALES_USER)) .with_cell(Lc::t("field-email", &LOCALES_USER))
.with_cell(user.email.as_str()), .with_cell(user.email.as_str()),
) )
.with_row( .with_row(
Row::new() table::Row::new()
.with_cell(Lc::t("field-display-name", &LOCALES_USER)) .with_cell(Lc::t("field-display-name", &LOCALES_USER))
.with_cell(user.display_name.as_deref().unwrap_or("-")), .with_cell(user.display_name.as_deref().unwrap_or("-")),
) )
.with_row( .with_row(
Row::new() table::Row::new()
.with_cell(Lc::t("field-language", &LOCALES_USER)) .with_cell(Lc::t("field-language", &LOCALES_USER))
.with_cell(user.language.as_deref().unwrap_or("-")), .with_cell(user.language.as_deref().unwrap_or("-")),
) )
.with_row( .with_row(
Row::new() table::Row::new()
.with_cell(Lc::t("field-timezone", &LOCALES_USER)) .with_cell(Lc::t("field-timezone", &LOCALES_USER))
.with_cell(user.timezone.as_deref().unwrap_or("-")), .with_cell(user.timezone.as_deref().unwrap_or("-")),
) )
.with_row( .with_row(
Row::new() table::Row::new()
.with_cell(Lc::t("col-status", &LOCALES_USER)) .with_cell(Lc::t("col-status", &LOCALES_USER))
.with_cell(Lc::t(status_key(status), &LOCALES_USER)), .with_cell(Lc::t(status_key(status), &LOCALES_USER)),
); );
@ -83,7 +82,7 @@ async fn profile_details(user: &user::Model, status: UserStatus, cx: &mut Contex
.render(cx) .render(cx)
.await; .await;
table = table.with_row( table = table.with_row(
Row::new() table::Row::new()
.with_cell("") .with_cell("")
.with_cell(Html::with(move |_| badge.clone())), .with_cell(Html::with(move |_| badge.clone())),
); );

View file

@ -2,7 +2,6 @@
use serde::Deserialize; use serde::Deserialize;
use pagetop::base::component::table::Row;
use pagetop::prelude::*; use pagetop::prelude::*;
use pagetop_htmx::prelude::*; use pagetop_htmx::prelude::*;
@ -313,22 +312,22 @@ async fn role_view_details(role: &role::Model, cx: &mut Context) -> Block {
let mut table = Table::new() let mut table = Table::new()
.with_prop(PropsOp::add_classes("user-admin-table")) .with_prop(PropsOp::add_classes("user-admin-table"))
.with_row( .with_row(
Row::new() table::Row::new()
.with_cell(Lc::t("field-machine-name", &LOCALES_USER)) .with_cell(Lc::t("field-machine-name", &LOCALES_USER))
.with_cell(role.machine_name.as_str()), .with_cell(role.machine_name.as_str()),
) )
.with_row( .with_row(
Row::new() table::Row::new()
.with_cell(Lc::t("field-label", &LOCALES_USER)) .with_cell(Lc::t("field-label", &LOCALES_USER))
.with_cell(role.label.as_str()), .with_cell(role.label.as_str()),
) )
.with_row( .with_row(
Row::new() table::Row::new()
.with_cell(Lc::t("field-description", &LOCALES_USER)) .with_cell(Lc::t("field-description", &LOCALES_USER))
.with_cell(role.description.as_deref().unwrap_or("-")), .with_cell(role.description.as_deref().unwrap_or("-")),
) )
.with_row( .with_row(
Row::new() table::Row::new()
.with_cell(Lc::t("field-weight", &LOCALES_USER)) .with_cell(Lc::t("field-weight", &LOCALES_USER))
.with_cell(role.weight.to_string()), .with_cell(role.weight.to_string()),
); );
@ -339,7 +338,7 @@ async fn role_view_details(role: &role::Model, cx: &mut Context) -> Block {
.render(cx) .render(cx)
.await; .await;
table = table.with_row( table = table.with_row(
Row::new() table::Row::new()
.with_cell("") .with_cell("")
.with_cell(Html::with(move |_| badge.clone())), .with_cell(Html::with(move |_| badge.clone())),
); );

View file

@ -2,7 +2,6 @@
use serde::Deserialize; use serde::Deserialize;
use pagetop::base::component::table::Row;
use pagetop::prelude::*; use pagetop::prelude::*;
use pagetop_htmx::prelude::*; use pagetop_htmx::prelude::*;
@ -517,32 +516,32 @@ async fn user_view_details(user: &user::Model, status: UserStatus, cx: &mut Cont
let mut table = Table::new() let mut table = Table::new()
.with_prop(PropsOp::add_classes("user-admin-table")) .with_prop(PropsOp::add_classes("user-admin-table"))
.with_row( .with_row(
Row::new() table::Row::new()
.with_cell(Lc::t("field-username-admin", &LOCALES_USER)) .with_cell(Lc::t("field-username-admin", &LOCALES_USER))
.with_cell(user.username.as_str()), .with_cell(user.username.as_str()),
) )
.with_row( .with_row(
Row::new() table::Row::new()
.with_cell(Lc::t("field-email", &LOCALES_USER)) .with_cell(Lc::t("field-email", &LOCALES_USER))
.with_cell(user.email.as_str()), .with_cell(user.email.as_str()),
) )
.with_row( .with_row(
Row::new() table::Row::new()
.with_cell(Lc::t("field-display-name", &LOCALES_USER)) .with_cell(Lc::t("field-display-name", &LOCALES_USER))
.with_cell(user.display_name.as_deref().unwrap_or("-")), .with_cell(user.display_name.as_deref().unwrap_or("-")),
) )
.with_row( .with_row(
Row::new() table::Row::new()
.with_cell(Lc::t("field-language", &LOCALES_USER)) .with_cell(Lc::t("field-language", &LOCALES_USER))
.with_cell(user.language.as_deref().unwrap_or("-")), .with_cell(user.language.as_deref().unwrap_or("-")),
) )
.with_row( .with_row(
Row::new() table::Row::new()
.with_cell(Lc::t("field-timezone", &LOCALES_USER)) .with_cell(Lc::t("field-timezone", &LOCALES_USER))
.with_cell(user.timezone.as_deref().unwrap_or("-")), .with_cell(user.timezone.as_deref().unwrap_or("-")),
) )
.with_row( .with_row(
Row::new() table::Row::new()
.with_cell(Lc::t("col-status", &LOCALES_USER)) .with_cell(Lc::t("col-status", &LOCALES_USER))
.with_cell(Lc::t(status_key(status), &LOCALES_USER)), .with_cell(Lc::t(status_key(status), &LOCALES_USER)),
); );
@ -553,7 +552,7 @@ async fn user_view_details(user: &user::Model, status: UserStatus, cx: &mut Cont
.render(cx) .render(cx)
.await; .await;
table = table.with_row( table = table.with_row(
Row::new() table::Row::new()
.with_cell("") .with_cell("")
.with_cell(Html::with(move |_| badge.clone())), .with_cell(Html::with(move |_| badge.clone())),
); );

View file

@ -2,7 +2,6 @@
use serde::Deserialize; use serde::Deserialize;
use pagetop::auth::CurrentUser;
use pagetop::prelude::*; use pagetop::prelude::*;
use crate::auth; use crate::auth;

View file

@ -5,9 +5,7 @@
//! si el usuario está autenticado, el [`crate::account::Account`] con sus datos ricos en las //! si el usuario está autenticado, el [`crate::account::Account`] con sus datos ricos en las
//! extensiones de la petición HTTP. //! extensiones de la petición HTTP.
use pagetop::auth::PermissionRef; use pagetop::prelude::*;
use pagetop::web::middleware::Next;
use pagetop::web::{Request, Response};
use crate::account::Account; use crate::account::Account;
use crate::session; use crate::session;
@ -17,7 +15,10 @@ use crate::session;
/// ///
/// - Siempre inserta [`pagetop::auth::CurrentUser`] (anónimo o autenticado). /// - Siempre inserta [`pagetop::auth::CurrentUser`] (anónimo o autenticado).
/// - Si hay sesión activa, inserta también el [`Account`] con roles y permisos. /// - Si hay sesión activa, inserta también el [`Account`] con roles y permisos.
pub(crate) async fn session_middleware(mut req: Request, next: Next) -> Response { pub(crate) async fn session_middleware(
mut req: web::Request,
next: web::middleware::Next,
) -> Response {
let (current_user, maybe_account) = session::resolve_session(req.headers()).await; let (current_user, maybe_account) = session::resolve_session(req.headers()).await;
req.extensions_mut().insert(current_user); req.extensions_mut().insert(current_user);

View file

@ -2,8 +2,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use pagetop::datetime::Utc; use pagetop::prelude::*;
use pagetop::html::SortDir;
use pagetop_seaorm::db::{ use pagetop_seaorm::db::{
ActiveModelTrait, ActiveValue, ColumnTrait, EntityTrait, Order, Paginated, PaginatorTrait, ActiveModelTrait, ActiveValue, ColumnTrait, EntityTrait, Order, Paginated, PaginatorTrait,
QueryFilter, QueryOrder, QuerySelect, Set, TransactionTrait, dbconn, flatten_txn_err, paginate, QueryFilter, QueryOrder, QuerySelect, Set, TransactionTrait, dbconn, flatten_txn_err, paginate,

View file

@ -2,9 +2,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use pagetop::datetime::Utc; use pagetop::prelude::*;
use pagetop::html::SortDir;
use pagetop::util;
use pagetop_seaorm::db::{ use pagetop_seaorm::db::{
ActiveModelTrait, ActiveValue, ColumnTrait, Condition, EntityTrait, Order, Paginated, ActiveModelTrait, ActiveValue, ColumnTrait, Condition, EntityTrait, Order, Paginated,
PaginatorTrait, QueryFilter, QueryOrder, Set, TransactionTrait, dbconn, flatten_txn_err, PaginatorTrait, QueryFilter, QueryOrder, Set, TransactionTrait, dbconn, flatten_txn_err,

View file

@ -1,9 +1,7 @@
//! Generación y verificación de tokens de un solo uso (reset de contraseña, verificación de //! Generación y verificación de tokens de un solo uso (reset de contraseña, verificación de
//! email...). //! email...).
use pagetop::datetime::{Duration, Utc}; use pagetop::prelude::*;
use sha2::{Digest, Sha256};
use pagetop_seaorm::db::{ use pagetop_seaorm::db::{
ActiveModelTrait, ActiveValue, ColumnTrait, EntityTrait, QueryFilter, Set, dbconn, ActiveModelTrait, ActiveValue, ColumnTrait, EntityTrait, QueryFilter, Set, dbconn,
}; };
@ -11,6 +9,8 @@ use pagetop_seaorm::db::{
use crate::entity::user_token; use crate::entity::user_token;
use crate::error::AuthError; use crate::error::AuthError;
use sha2::{Digest, Sha256};
// **< Generación de tokens >*********************************************************************** // **< Generación de tokens >***********************************************************************
/// Genera un token URL-safe de 43 caracteres (32 bytes -> base64url sin padding). /// Genera un token URL-safe de 43 caracteres (32 bytes -> base64url sin padding).