init
This commit is contained in:
10
backend/migration/Cargo.toml
Normal file
10
backend/migration/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "migration"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
sea-orm-migration = { version = "1.1.14" }
|
||||
argon2 = "0.5"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
rand = "0.8"
|
||||
34
backend/migration/src/lib.rs
Normal file
34
backend/migration/src/lib.rs
Normal file
@ -0,0 +1,34 @@
|
||||
pub use sea_orm_migration::prelude::*;
|
||||
|
||||
mod m20220101_000001_create_users;
|
||||
mod m20220101_000002_create_refresh_tokens;
|
||||
mod m20220101_000003_create_roles;
|
||||
mod m20220101_000004_create_permissions;
|
||||
mod m20220101_000005_create_menus;
|
||||
mod m20220101_000006_create_rbac_relations;
|
||||
mod m20220101_000007_create_departments;
|
||||
mod m20220101_000008_add_keep_alive_to_menus;
|
||||
mod m20220101_000009_create_request_logs;
|
||||
// 新增岗位与用户岗位关联
|
||||
mod m20220101_000010_create_positions;
|
||||
|
||||
pub struct Migrator;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigratorTrait for Migrator {
|
||||
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
||||
vec![
|
||||
Box::new(m20220101_000001_create_users::Migration),
|
||||
Box::new(m20220101_000002_create_refresh_tokens::Migration),
|
||||
Box::new(m20220101_000003_create_roles::Migration),
|
||||
Box::new(m20220101_000004_create_permissions::Migration),
|
||||
Box::new(m20220101_000005_create_menus::Migration),
|
||||
Box::new(m20220101_000006_create_rbac_relations::Migration),
|
||||
Box::new(m20220101_000007_create_departments::Migration),
|
||||
Box::new(m20220101_000008_add_keep_alive_to_menus::Migration),
|
||||
Box::new(m20220101_000009_create_request_logs::Migration),
|
||||
// 注册岗位迁移
|
||||
Box::new(m20220101_000010_create_positions::Migration),
|
||||
]
|
||||
}
|
||||
}
|
||||
65
backend/migration/src/m20220101_000001_create_users.rs
Normal file
65
backend/migration/src/m20220101_000001_create_users.rs
Normal file
@ -0,0 +1,65 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
use sea_orm_migration::sea_orm::DatabaseBackend;
|
||||
use argon2::{Argon2, password_hash::{SaltString, PasswordHasher}};
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Users::Table)
|
||||
.if_not_exists()
|
||||
.col(ColumnDef::new(Users::Id).big_integer().not_null().auto_increment().primary_key())
|
||||
.col(ColumnDef::new(Users::Username).string().not_null().unique_key())
|
||||
.col(ColumnDef::new(Users::PasswordHash).string().not_null())
|
||||
.col(ColumnDef::new(Users::Nickname).string().null())
|
||||
.col(ColumnDef::new(Users::Status).integer().not_null().default(1))
|
||||
.col(ColumnDef::new(Users::CreatedAt).timestamp().not_null().default(Expr::current_timestamp()))
|
||||
.col(ColumnDef::new(Users::UpdatedAt).timestamp().not_null().default(Expr::current_timestamp()))
|
||||
.to_owned()
|
||||
)
|
||||
.await?;
|
||||
|
||||
// seed admin user (cross-DB)
|
||||
let salt = SaltString::generate(&mut rand::thread_rng());
|
||||
let hash = Argon2::default().hash_password("Admin@123".as_bytes(), &salt).unwrap().to_string();
|
||||
let backend = manager.get_database_backend();
|
||||
let conn = manager.get_connection();
|
||||
match backend {
|
||||
DatabaseBackend::MySql => {
|
||||
conn.execute_unprepared(&format!(
|
||||
"INSERT INTO users (username, password_hash, nickname, status) VALUES ('admin', '{}', 'Administrator', 1) ON DUPLICATE KEY UPDATE username=username",
|
||||
hash
|
||||
))
|
||||
.await?;
|
||||
}
|
||||
DatabaseBackend::Postgres => {
|
||||
conn.execute_unprepared(&format!(
|
||||
"INSERT INTO users (username, password_hash, nickname, status) VALUES ('admin', '{}', 'Administrator', 1) ON CONFLICT (username) DO NOTHING",
|
||||
hash
|
||||
))
|
||||
.await?;
|
||||
}
|
||||
DatabaseBackend::Sqlite => {
|
||||
conn.execute_unprepared(&format!(
|
||||
"INSERT OR IGNORE INTO users (username, password_hash, nickname, status) VALUES ('admin', '{}', 'Administrator', 1)",
|
||||
hash
|
||||
))
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager.drop_table(Table::drop().table(Users::Table).to_owned()).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Iden)]
|
||||
enum Users { Table, Id, Username, PasswordHash, Nickname, Status, CreatedAt, UpdatedAt }
|
||||
@ -0,0 +1,31 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(RefreshTokens::Table)
|
||||
.if_not_exists()
|
||||
.col(ColumnDef::new(RefreshTokens::Id).big_integer().not_null().auto_increment().primary_key())
|
||||
.col(ColumnDef::new(RefreshTokens::UserId).big_integer().not_null())
|
||||
.col(ColumnDef::new(RefreshTokens::TokenHash).string().not_null().unique_key())
|
||||
.col(ColumnDef::new(RefreshTokens::ExpiresAt).timestamp().not_null())
|
||||
.col(ColumnDef::new(RefreshTokens::CreatedAt).timestamp().not_null().default(Expr::current_timestamp()))
|
||||
.to_owned()
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager.drop_table(Table::drop().table(RefreshTokens::Table).to_owned()).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Iden)]
|
||||
enum RefreshTokens { Table, Id, UserId, TokenHash, ExpiresAt, CreatedAt }
|
||||
33
backend/migration/src/m20220101_000003_create_roles.rs
Normal file
33
backend/migration/src/m20220101_000003_create_roles.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Roles::Table)
|
||||
.if_not_exists()
|
||||
.col(ColumnDef::new(Roles::Id).big_integer().not_null().auto_increment().primary_key())
|
||||
.col(ColumnDef::new(Roles::Name).string().not_null())
|
||||
.col(ColumnDef::new(Roles::Code).string().not_null().unique_key())
|
||||
.col(ColumnDef::new(Roles::Description).string().null())
|
||||
.col(ColumnDef::new(Roles::Status).integer().not_null().default(1))
|
||||
.col(ColumnDef::new(Roles::CreatedAt).timestamp().not_null().default(Expr::current_timestamp()))
|
||||
.col(ColumnDef::new(Roles::UpdatedAt).timestamp().not_null().default(Expr::current_timestamp()))
|
||||
.to_owned()
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager.drop_table(Table::drop().table(Roles::Table).to_owned()).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Iden)]
|
||||
enum Roles { Table, Id, Name, Code, Description, Status, CreatedAt, UpdatedAt }
|
||||
17
backend/migration/src/m20220101_000004_create_permissions.rs
Normal file
17
backend/migration/src/m20220101_000004_create_permissions.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, _manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
// 占位迁移:原始迁移文件缺失,但已应用。此处为空实现以满足迁移链完整性。
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
// 占位迁移,无需回滚实际变更
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
39
backend/migration/src/m20220101_000005_create_menus.rs
Normal file
39
backend/migration/src/m20220101_000005_create_menus.rs
Normal file
@ -0,0 +1,39 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Menus::Table)
|
||||
.if_not_exists()
|
||||
.col(ColumnDef::new(Menus::Id).big_integer().not_null().auto_increment().primary_key())
|
||||
.col(ColumnDef::new(Menus::ParentId).big_integer().null())
|
||||
.col(ColumnDef::new(Menus::Name).string().not_null())
|
||||
.col(ColumnDef::new(Menus::Path).string().null())
|
||||
.col(ColumnDef::new(Menus::Component).string().null())
|
||||
.col(ColumnDef::new(Menus::Type).integer().not_null())
|
||||
.col(ColumnDef::new(Menus::Icon).string().null())
|
||||
.col(ColumnDef::new(Menus::OrderNo).integer().not_null().default(0))
|
||||
.col(ColumnDef::new(Menus::Visible).boolean().not_null().default(true))
|
||||
.col(ColumnDef::new(Menus::Status).integer().not_null().default(1))
|
||||
.col(ColumnDef::new(Menus::Perms).string().null())
|
||||
.col(ColumnDef::new(Menus::CreatedAt).timestamp().not_null().default(Expr::current_timestamp()))
|
||||
.col(ColumnDef::new(Menus::UpdatedAt).timestamp().not_null().default(Expr::current_timestamp()))
|
||||
.to_owned()
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager.drop_table(Table::drop().table(Menus::Table).to_owned()).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Iden)]
|
||||
enum Menus { Table, Id, ParentId, Name, Path, Component, Type, Icon, OrderNo, Visible, Status, Perms, CreatedAt, UpdatedAt }
|
||||
@ -0,0 +1,46 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
// user_roles
|
||||
manager.create_table(
|
||||
Table::create()
|
||||
.table(UserRoles::Table)
|
||||
.if_not_exists()
|
||||
.col(ColumnDef::new(UserRoles::Id).big_integer().not_null().auto_increment().primary_key())
|
||||
.col(ColumnDef::new(UserRoles::UserId).big_integer().not_null())
|
||||
.col(ColumnDef::new(UserRoles::RoleId).big_integer().not_null())
|
||||
.index(Index::create().name("idx_user_role_uniq").col(UserRoles::UserId).col(UserRoles::RoleId).unique())
|
||||
.to_owned()
|
||||
).await?;
|
||||
|
||||
// role_menus
|
||||
manager.create_table(
|
||||
Table::create()
|
||||
.table(RoleMenus::Table)
|
||||
.if_not_exists()
|
||||
.col(ColumnDef::new(RoleMenus::Id).big_integer().not_null().auto_increment().primary_key())
|
||||
.col(ColumnDef::new(RoleMenus::RoleId).big_integer().not_null())
|
||||
.col(ColumnDef::new(RoleMenus::MenuId).big_integer().not_null())
|
||||
.index(Index::create().name("idx_role_menu_uniq").col(RoleMenus::RoleId).col(RoleMenus::MenuId).unique())
|
||||
.to_owned()
|
||||
).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager.drop_table(Table::drop().table(RoleMenus::Table).to_owned()).await?;
|
||||
manager.drop_table(Table::drop().table(UserRoles::Table).to_owned()).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Iden)]
|
||||
enum UserRoles { Table, Id, UserId, RoleId }
|
||||
|
||||
#[derive(Iden)]
|
||||
enum RoleMenus { Table, Id, RoleId, MenuId }
|
||||
53
backend/migration/src/m20220101_000007_create_departments.rs
Normal file
53
backend/migration/src/m20220101_000007_create_departments.rs
Normal file
@ -0,0 +1,53 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
// departments
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Departments::Table)
|
||||
.if_not_exists()
|
||||
.col(ColumnDef::new(Departments::Id).big_integer().not_null().auto_increment().primary_key())
|
||||
.col(ColumnDef::new(Departments::ParentId).big_integer().null())
|
||||
.col(ColumnDef::new(Departments::Name).string().not_null())
|
||||
.col(ColumnDef::new(Departments::OrderNo).integer().not_null().default(0))
|
||||
.col(ColumnDef::new(Departments::Status).integer().not_null().default(1))
|
||||
.col(ColumnDef::new(Departments::CreatedAt).timestamp().not_null().default(Expr::current_timestamp()))
|
||||
.col(ColumnDef::new(Departments::UpdatedAt).timestamp().not_null().default(Expr::current_timestamp()))
|
||||
.to_owned()
|
||||
)
|
||||
.await?;
|
||||
|
||||
// user_departments
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(UserDepartments::Table)
|
||||
.if_not_exists()
|
||||
.col(ColumnDef::new(UserDepartments::Id).big_integer().not_null().auto_increment().primary_key())
|
||||
.col(ColumnDef::new(UserDepartments::UserId).big_integer().not_null())
|
||||
.col(ColumnDef::new(UserDepartments::DepartmentId).big_integer().not_null())
|
||||
.index(Index::create().name("idx_user_department_uniq").col(UserDepartments::UserId).col(UserDepartments::DepartmentId).unique())
|
||||
.to_owned()
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager.drop_table(Table::drop().table(UserDepartments::Table).to_owned()).await?;
|
||||
manager.drop_table(Table::drop().table(Departments::Table).to_owned()).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Iden)]
|
||||
enum Departments { Table, Id, ParentId, Name, OrderNo, Status, CreatedAt, UpdatedAt }
|
||||
|
||||
#[derive(Iden)]
|
||||
enum UserDepartments { Table, Id, UserId, DepartmentId }
|
||||
@ -0,0 +1,35 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.alter_table(
|
||||
Table::alter()
|
||||
.table(Menus::Table)
|
||||
.add_column(ColumnDef::new(Menus::KeepAlive).boolean().not_null().default(true))
|
||||
.to_owned()
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.alter_table(
|
||||
Table::alter()
|
||||
.table(Menus::Table)
|
||||
.drop_column(Menus::KeepAlive)
|
||||
.to_owned()
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Menus {
|
||||
Table,
|
||||
KeepAlive,
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(RequestLogs::Table)
|
||||
.if_not_exists()
|
||||
.col(ColumnDef::new(RequestLogs::Id).big_integer().not_null().auto_increment().primary_key())
|
||||
.col(ColumnDef::new(RequestLogs::Path).string().not_null())
|
||||
.col(ColumnDef::new(RequestLogs::Method).string().not_null())
|
||||
.col(ColumnDef::new(RequestLogs::RequestParams).text().null())
|
||||
.col(ColumnDef::new(RequestLogs::ResponseParams).text().null())
|
||||
.col(ColumnDef::new(RequestLogs::StatusCode).integer().not_null().default(200))
|
||||
.col(ColumnDef::new(RequestLogs::UserId).big_integer().null())
|
||||
.col(ColumnDef::new(RequestLogs::Username).string().null())
|
||||
.col(ColumnDef::new(RequestLogs::RequestTime).timestamp().not_null().default(Expr::current_timestamp()))
|
||||
.col(ColumnDef::new(RequestLogs::DurationMs).big_integer().not_null().default(0))
|
||||
.col(ColumnDef::new(RequestLogs::CreatedAt).timestamp().not_null().default(Expr::current_timestamp()))
|
||||
.to_owned()
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager.drop_table(Table::drop().table(RequestLogs::Table).to_owned()).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Iden)]
|
||||
enum RequestLogs {
|
||||
Table,
|
||||
Id,
|
||||
Path,
|
||||
Method,
|
||||
RequestParams,
|
||||
ResponseParams,
|
||||
StatusCode,
|
||||
UserId,
|
||||
Username,
|
||||
RequestTime,
|
||||
DurationMs,
|
||||
CreatedAt,
|
||||
}
|
||||
52
backend/migration/src/m20220101_000010_create_positions.rs
Normal file
52
backend/migration/src/m20220101_000010_create_positions.rs
Normal file
@ -0,0 +1,52 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
// positions
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Positions::Table)
|
||||
.if_not_exists()
|
||||
.col(ColumnDef::new(Positions::Id).big_integer().not_null().auto_increment().primary_key())
|
||||
.col(ColumnDef::new(Positions::Name).string().not_null())
|
||||
.col(ColumnDef::new(Positions::Code).string().not_null().unique_key())
|
||||
.col(ColumnDef::new(Positions::Description).string().null())
|
||||
.col(ColumnDef::new(Positions::Status).integer().not_null().default(1))
|
||||
.col(ColumnDef::new(Positions::OrderNo).integer().not_null().default(0))
|
||||
.col(ColumnDef::new(Positions::CreatedAt).timestamp().not_null().default(Expr::current_timestamp()))
|
||||
.col(ColumnDef::new(Positions::UpdatedAt).timestamp().not_null().default(Expr::current_timestamp()))
|
||||
.to_owned()
|
||||
)
|
||||
.await?;
|
||||
|
||||
// user_positions
|
||||
manager.create_table(
|
||||
Table::create()
|
||||
.table(UserPositions::Table)
|
||||
.if_not_exists()
|
||||
.col(ColumnDef::new(UserPositions::Id).big_integer().not_null().auto_increment().primary_key())
|
||||
.col(ColumnDef::new(UserPositions::UserId).big_integer().not_null())
|
||||
.col(ColumnDef::new(UserPositions::PositionId).big_integer().not_null())
|
||||
.index(Index::create().name("idx_user_position_uniq").col(UserPositions::UserId).col(UserPositions::PositionId).unique())
|
||||
.to_owned()
|
||||
).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager.drop_table(Table::drop().table(UserPositions::Table).to_owned()).await?;
|
||||
manager.drop_table(Table::drop().table(Positions::Table).to_owned()).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Iden)]
|
||||
enum Positions { Table, Id, Name, Code, Description, Status, OrderNo, CreatedAt, UpdatedAt }
|
||||
|
||||
#[derive(Iden)]
|
||||
enum UserPositions { Table, Id, UserId, PositionId }
|
||||
Reference in New Issue
Block a user