feat(db): 添加 student/teacher/parent 角色种子 — 日记权限分配

This commit is contained in:
iven
2026-06-01 22:37:52 +08:00
parent 6cb288b4f2
commit b3fc066aac
2 changed files with 102 additions and 0 deletions

View File

@@ -70,6 +70,7 @@ mod m20260531_000181_create_teacher_profiles;
mod m20260531_000182_create_user_settings;
mod m20260531_000183_diary_indexes_and_fts;
mod m20260531_000184_diary_seed_data;
mod m20260601_000300_diary_role_seed;
pub struct Migrator;
@@ -146,6 +147,7 @@ impl MigratorTrait for Migrator {
Box::new(m20260531_000182_create_user_settings::Migration),
Box::new(m20260531_000183_diary_indexes_and_fts::Migration),
Box::new(m20260531_000184_diary_seed_data::Migration),
Box::new(m20260601_000300_diary_role_seed::Migration),
]
}
}

View File

@@ -0,0 +1,100 @@
// 暖记角色种子 — student/teacher/parent 角色 + 权限分配
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> {
let conn = manager.get_connection();
let tid = "'00000000-0000-0000-0000-000000000000'::uuid";
// 插入 student/teacher/parent 角色
let roles = [
("student", "学生", "学生 — 创建和管理自己的日记", false),
("teacher", "老师", "老师 — 创建班级、布置主题、点评日记", false),
("parent", "家长", "家长 — 查看和管理孩子的日记数据", false),
];
for (code, name, desc, is_system) in &roles {
let sys_flag = if *is_system { "true" } else { "false" };
let sql = format!(
r#"INSERT INTO roles (id, tenant_id, name, code, description, is_system, created_at, updated_at, created_by, updated_by, version)
VALUES (gen_random_uuid(), {tid}, '{name}', '{code}', '{desc}', {sys_flag}, now(), now(), {tid}, {tid}, 1)
ON CONFLICT (tenant_id, code) WHERE deleted_at IS NULL DO NOTHING"#,
);
conn.execute(sea_orm::Statement::from_string(
sea_orm::DatabaseBackend::Postgres,
sql,
))
.await
.map_err(|e| DbErr::Custom(e.to_string()))?;
}
// student 权限: diary.journal.create, diary.journal.read
// teacher 权限: diary.journal.create, diary.journal.read, diary.class.manage, diary.topic.assign, diary.comment.write
// parent 权限: diary.journal.read, diary.parent.bind
let role_permissions = [
("student", "diary.journal.create"),
("student", "diary.journal.read"),
("teacher", "diary.journal.create"),
("teacher", "diary.journal.read"),
("teacher", "diary.class.manage"),
("teacher", "diary.topic.assign"),
("teacher", "diary.comment.write"),
("parent", "diary.journal.read"),
("parent", "diary.parent.bind"),
];
for (role_code, perm_code) in &role_permissions {
let sql = format!(
r#"INSERT INTO role_permissions (id, role_id, permission_id, tenant_id, created_at, updated_at, created_by, updated_by, version)
SELECT gen_random_uuid(), r.id, p.id, r.tenant_id, now(), now(), {tid}, {tid}, 1
FROM roles r
JOIN permissions p ON p.tenant_id = r.tenant_id
WHERE r.code = '{role_code}' AND r.tenant_id = {tid} AND r.deleted_at IS NULL
AND p.code = '{perm_code}' AND p.deleted_at IS NULL
ON CONFLICT DO NOTHING"#,
);
conn.execute(sea_orm::Statement::from_string(
sea_orm::DatabaseBackend::Postgres,
sql,
))
.await
.map_err(|e| DbErr::Custom(e.to_string()))?;
}
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
let conn = manager.get_connection();
let tid_str = "WHERE tenant_id = '00000000-0000-0000-0000-000000000000'";
// 先删除 role_permissions 引用
for role_code in &["student", "teacher", "parent"] {
conn.execute(sea_orm::Statement::from_string(
sea_orm::DatabaseBackend::Postgres,
format!(
"DELETE FROM role_permissions WHERE role_id IN (SELECT id FROM roles WHERE code = '{role_code}' {tid_str})"
),
))
.await
.map_err(|e| DbErr::Custom(e.to_string()))?;
}
// 再删除角色
for role_code in &["student", "teacher", "parent"] {
conn.execute(sea_orm::Statement::from_string(
sea_orm::DatabaseBackend::Postgres,
format!("DELETE FROM roles WHERE code = '{role_code}' {tid_str}"),
))
.await
.map_err(|e| DbErr::Custom(e.to_string()))?;
}
Ok(())
}
}