♻️ Major code restructuring

This commit is contained in:
Manuel Cillero 2024-02-09 14:05:38 +01:00
parent a96e203bb3
commit fa66d628a0
221 changed files with 228 additions and 315 deletions

View file

@ -0,0 +1,19 @@
[package]
name = "pagetop-user"
version = "0.0.14"
edition = "2021"
authors = [
"Manuel Cillero <manuel@cillero.es>"
]
description = """\
Module to add user management, roles, permissions and sessions in applications developed with \
PageTop.\
"""
homepage = "https://pagetop.cillero.es"
repository = "https://github.com/manuelcillero/pagetop"
license = "MIT OR Apache-2.0"
[dependencies]
pagetop = { version = "0.0", path = "../../", features = ["database"], default-features = false }
serde = { version = "1.0", features = ["derive"] }

View file

@ -0,0 +1,27 @@
Módulo para añadir gestión de usuarios, roles, permisos y sesiones en aplicaciones desarrolladas con
**PageTop**.
[PageTop](https://github.com/manuelcillero/pagetop/tree/main/pagetop), es un entorno de desarrollo
basado en algunos de los *crates* más estables y populares del ecosistema Rust para proporcionar
APIs, patrones de desarrollo y buenas prácticas para la creación de soluciones web SSR (*Server-Side
Rendering*).
# 🚧 Advertencia
**PageTop** sólo libera actualmente versiones de desarrollo. La API no es estable y los cambios son
constantes. No puede considerarse preparado hasta que se libere la versión **0.1.0**.
# 📜 Licencia
Este proyecto tiene licencia, de hecho tiene dos, puedes aplicar cualquiera de las siguientes a tu
elección:
* Licencia Apache versión 2.0
([LICENSE-APACHE](https://github.com/manuelcillero/pagetop/blob/main/LICENSE-APACHE) o
[http://www.apache.org/licenses/LICENSE-2.0]).
* Licencia MIT
([LICENSE-MIT](https://github.com/manuelcillero/pagetop/blob/main/LICENSE-MIT) o
[http://opensource.org/licenses/MIT]).

View file

@ -0,0 +1,65 @@
use pagetop::prelude::*;
static_locales!(LOCALES_USER);
mod migration;
#[derive(AssignHandle)]
pub struct User;
impl PackageTrait for User {
fn name(&self) -> L10n {
L10n::t("package_name", &LOCALES_USER)
}
fn description(&self) -> L10n {
L10n::t("package_description", &LOCALES_USER)
}
fn configure_service(&self, scfg: &mut service::web::ServiceConfig) {
scfg.route("/user/login", service::web::get().to(login));
}
fn migrations(&self) -> Vec<MigrationItem> {
migrations![
m20220312_000001_create_table_role,
m20220312_000002_create_table_role_permission,
m20220312_000003_create_table_user,
m20220312_000004_create_table_user_role,
]
}
}
async fn login(request: service::HttpRequest) -> ResultPage<Markup, ErrorPage> {
Page::new(request)
.with_title(L10n::n("Identificación del usuario"))
.with_component_in(
"content",
Wrapper::new()
.with_id("welcome")
.add_component(form_login()),
)
.render()
}
fn form_login() -> Form {
Form::new()
.with_id("user-login")
.with_element(
form::Input::textfield()
.with_name("name")
.with_label(L10n::t("username", &LOCALES_USER))
.with_help_text(
L10n::t("username_help", &LOCALES_USER)
.with_arg("app", config::SETTINGS.app.name.to_owned()),
)
.with_autofocus(true),
)
.with_element(
form::Input::password()
.with_name("pass")
.with_label(L10n::t("password", &LOCALES_USER))
.with_help_text(L10n::t("password_help", &LOCALES_USER)),
)
.with_element(form::ActionButton::submit().with_value(L10n::t("login", &LOCALES_USER)))
}

View file

@ -0,0 +1,8 @@
package_name = User
package_description = Manages the user registration and login system.
username = User name
password = Password
username_help = Enter your { $app } username.
password_help = Enter the password that accompanies your username.
login = Log in

View file

@ -0,0 +1,8 @@
package_name = Usuario
package_description = Gestiona el registro de usuarios y el sistema de accesos.
username = Nombre de usuario
password = Contraseña
username_help = Introduzca su nombre de usuario en { $app }.
password_help = Introduzca la contraseña asociada a su nombre de usuario.
login = Iniciar sesión

View file

@ -0,0 +1,4 @@
pub mod m20220312_000001_create_table_role;
pub mod m20220312_000002_create_table_role_permission;
pub mod m20220312_000003_create_table_user;
pub mod m20220312_000004_create_table_user_role;

View file

@ -0,0 +1,71 @@
use pagetop::prelude::*;
#[rustfmt::skip]
#[derive(Iden)]
enum Role {
Table, // role: Store user roles.
Rid, // Primary Key: Unique role ID.
Name, // Unique role name.
Weight, // The weight of this role in listings and the user interface.
}
new_migration!(Migration);
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(Role::Table)
.if_not_exists()
.col(
ColumnDef::new(Role::Rid)
.unsigned()
.not_null()
.auto_increment()
.primary_key(),
)
.col(
ColumnDef::new(Role::Name)
.string_len(64)
.not_null()
.unique_key(),
)
.col(
ColumnDef::new(Role::Weight)
.integer()
.not_null()
.default(10),
)
// INDEXES.
.index(
Index::create()
.name("weight-name")
.col(Role::Weight)
.col(Role::Name),
)
.to_owned(),
)
.await?;
// Built-in roles.
db::exec::<InsertStatement>(
Query::insert()
.into_table(Role::Table)
.columns(vec![Role::Name, Role::Weight])
.values_panic(vec!["anonymous".into(), "1".into()])
.values_panic(vec!["authenticated".into(), "2".into()])
.values_panic(vec!["administrator".into(), "3".into()]),
)
.await
.map(|_| ())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(Role::Table).to_owned())
.await
}
}

View file

@ -0,0 +1,64 @@
use pagetop::prelude::*;
#[rustfmt::skip]
#[derive(Iden)]
enum RolePermission {
Table, // role_permission: Stores the permissions assigned to user roles.
Rid, // Foreign Key: Role::Rid.
Permission, // A single permission granted to the role identified by Rid.
}
#[derive(Iden)]
enum Role {
Table,
Rid,
/* ... */
}
new_migration!(Migration);
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(RolePermission::Table)
.if_not_exists()
.col(ColumnDef::new(RolePermission::Rid).unsigned().not_null())
.col(
ColumnDef::new(RolePermission::Permission)
.string_len(128)
.not_null(),
)
// INDEXES.
.primary_key(
Index::create()
.col(RolePermission::Rid)
.col(RolePermission::Permission),
)
.index(
Index::create()
.name("permission")
.col(RolePermission::Permission),
)
.foreign_key(
ForeignKey::create()
.name("fk_role_permission-rid")
.from(RolePermission::Table, RolePermission::Rid)
.to(Role::Table, Role::Rid)
.on_delete(ForeignKeyAction::Restrict)
.on_update(ForeignKeyAction::Restrict),
)
.to_owned(),
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(RolePermission::Table).to_owned())
.await
}
}

View file

@ -0,0 +1,60 @@
use pagetop::prelude::*;
#[rustfmt::skip]
#[derive(Iden)]
enum User {
Table, // user: Stores user data.
Uid, // Primary Key: Unique user ID.
Name, // Unique user name.
Pass, // User's password (hashed).
Mail, // User's e-mail address.
Created, // Timestamp for when user was created.
Changed, // Timestamp for when user was changed.
Access, // Timestamp for previous time user accessed the site.
Login, // Timestamp for user's last login.
Status, // Whether the user is active(1) or blocked(0).
Timezone, // User's time zone.
}
new_migration!(Migration);
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(User::Table)
.if_not_exists()
.col(
ColumnDef::new(User::Uid)
.unsigned()
.not_null()
.primary_key(),
)
.col(
ColumnDef::new(User::Name)
.string_len(60)
.not_null()
.unique_key(),
)
.col(ColumnDef::new(User::Pass).string_len(128).not_null())
.col(ColumnDef::new(User::Mail).string_len(255))
.col(ColumnDef::new(User::Created).timestamp().not_null())
.col(ColumnDef::new(User::Changed).timestamp().not_null())
.col(ColumnDef::new(User::Access).timestamp().not_null())
.col(ColumnDef::new(User::Login).timestamp().not_null())
.col(ColumnDef::new(User::Status).boolean().not_null())
.col(ColumnDef::new(User::Timezone).string_len(32))
.to_owned(),
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(User::Table).to_owned())
.await
}
}

View file

@ -0,0 +1,66 @@
use pagetop::prelude::*;
#[rustfmt::skip]
#[derive(Iden)]
enum UserRole {
Table, // user_role: Maps users to roles.
Uid, // Foreign Key: User::Uid for user.
Rid, // Foreign Key: Role::Rid for role.
}
#[derive(Iden)]
enum User {
Table,
Uid,
/* ... */
}
#[derive(Iden)]
enum Role {
Table,
Rid,
/* ... */
}
new_migration!(Migration);
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(UserRole::Table)
.if_not_exists()
.col(ColumnDef::new(UserRole::Uid).unsigned().not_null())
.col(ColumnDef::new(UserRole::Rid).unsigned().not_null())
// INDEXES.
.primary_key(Index::create().col(UserRole::Uid).col(UserRole::Rid))
.foreign_key(
ForeignKey::create()
.name("fk_user_role-uid")
.from(UserRole::Table, UserRole::Uid)
.to(User::Table, User::Uid)
.on_delete(ForeignKeyAction::Restrict)
.on_update(ForeignKeyAction::Restrict),
)
.foreign_key(
ForeignKey::create()
.name("fk_user_role-rid")
.from(UserRole::Table, UserRole::Rid)
.to(Role::Table, Role::Rid)
.on_delete(ForeignKeyAction::Restrict)
.on_update(ForeignKeyAction::Restrict),
)
.to_owned(),
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(UserRole::Table).to_owned())
.await
}
}