You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
717 lines
22 KiB
Python
717 lines
22 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from collections.abc import Iterable
|
|
from typing import Any
|
|
|
|
from sqlalchemy import select
|
|
|
|
from iti.applications.common.enums import GenderEnum, MenuTypeEnum, StatusEnum, SysConfigType
|
|
from iti.applications.extensions import db
|
|
from iti_system.models import Role, SysConfig, SysDictData, SysDictType, SysMenu, User
|
|
from iti.modules import ModuleMenuSeed
|
|
from iti.modules.registry import ModuleRegistry
|
|
|
|
|
|
@dataclass
|
|
class SeedCounter:
|
|
created: int = 0
|
|
updated: int = 0
|
|
skipped: int = 0
|
|
|
|
def as_dict(self) -> dict[str, int]:
|
|
return {
|
|
"created": self.created,
|
|
"updated": self.updated,
|
|
"skipped": self.skipped,
|
|
}
|
|
|
|
|
|
SYSTEM_MENU_ID = "b3af308711954e62ba7471891b82f721"
|
|
USER_MENU_ID = "93e1c7448c144f60875c4725dfa93b5a"
|
|
ROLE_MENU_ID = "8ac71de8a14c413997f7f81f5fcf343c"
|
|
DEPT_MENU_ID = "5d76b276594349b5bfbed42da656bd53"
|
|
MENU_MENU_ID = "b3f689cf6d594f94aeed912bd5c7dd80"
|
|
CONFIG_MENU_ID = "42a830108d9c49bca4e0108aba27a3cf"
|
|
DICT_MENU_ID = "50d583e8c8584d43ab94939420dce0cb"
|
|
LOG_MENU_ID = "774da56753514b4eafc913162970f4f1"
|
|
|
|
|
|
DEFAULT_ROLES = [
|
|
{
|
|
"name": "管理员",
|
|
"code": "ADMIN",
|
|
"desc": "系统默认管理员",
|
|
"sort": 0,
|
|
},
|
|
{
|
|
"name": "普通角色",
|
|
"code": "COMMON",
|
|
"desc": "一般角色",
|
|
"sort": 100,
|
|
},
|
|
]
|
|
|
|
DEFAULT_USERS = [
|
|
{
|
|
"username": "admin",
|
|
"password": "123456",
|
|
"realname": "管理员",
|
|
"phone": "18888888888",
|
|
"email": "a@a.com",
|
|
"avatar": "",
|
|
"gender": GenderEnum.SECURE.value,
|
|
"desc": "系统默认管理员",
|
|
"role_codes": ["ADMIN"],
|
|
},
|
|
]
|
|
|
|
DEFAULT_MENUS = [
|
|
{
|
|
"id": SYSTEM_MENU_ID,
|
|
"name": "System",
|
|
"type": MenuTypeEnum.CATALOG.value,
|
|
"path": "/system",
|
|
"sort": 0,
|
|
"meta": {"title": "系统管理", "icon": "ion:settings-outline"},
|
|
},
|
|
{
|
|
"id": USER_MENU_ID,
|
|
"name": "User",
|
|
"type": MenuTypeEnum.MENU.value,
|
|
"path": "/system/user",
|
|
"component": "/system/user/list",
|
|
"sort": 1,
|
|
"parent_id": SYSTEM_MENU_ID,
|
|
"auth_code": "system:user:list",
|
|
"meta": {"title": "system.user.title", "icon": "carbon:user"},
|
|
},
|
|
{
|
|
"id": ROLE_MENU_ID,
|
|
"name": "Role",
|
|
"type": MenuTypeEnum.MENU.value,
|
|
"path": "/system/role",
|
|
"component": "/system/role/list",
|
|
"sort": 2,
|
|
"parent_id": SYSTEM_MENU_ID,
|
|
"auth_code": "system:role:list",
|
|
"meta": {"title": "角色管理", "icon": "carbon:user-role"},
|
|
},
|
|
{
|
|
"id": DEPT_MENU_ID,
|
|
"name": "Dept",
|
|
"type": MenuTypeEnum.MENU.value,
|
|
"path": "/system/dept",
|
|
"component": "/system/dept/list",
|
|
"sort": 3,
|
|
"parent_id": SYSTEM_MENU_ID,
|
|
"auth_code": "system:dept:list",
|
|
"meta": {"title": "部门管理", "icon": "carbon:container-services", "order": 3},
|
|
},
|
|
{
|
|
"id": MENU_MENU_ID,
|
|
"name": "Menu",
|
|
"type": MenuTypeEnum.MENU.value,
|
|
"path": "/system/menu",
|
|
"component": "/system/menu/list",
|
|
"sort": 4,
|
|
"parent_id": SYSTEM_MENU_ID,
|
|
"auth_code": "system:menu:list",
|
|
"meta": {"title": "菜单管理", "icon": "carbon:menu", "badge": ""},
|
|
},
|
|
{
|
|
"id": CONFIG_MENU_ID,
|
|
"name": "SysConfig",
|
|
"type": MenuTypeEnum.MENU.value,
|
|
"path": "/system/config",
|
|
"component": "/system/config/list",
|
|
"sort": 5,
|
|
"parent_id": SYSTEM_MENU_ID,
|
|
"auth_code": "system:config:list",
|
|
"meta": {"title": "系统配置", "icon": "carbon:document-configuration", "order": 5},
|
|
},
|
|
{
|
|
"id": DICT_MENU_ID,
|
|
"name": "SysDict",
|
|
"type": MenuTypeEnum.MENU.value,
|
|
"path": "/system/dict",
|
|
"component": "/system/dict/list",
|
|
"sort": 6,
|
|
"parent_id": SYSTEM_MENU_ID,
|
|
"auth_code": "system:dict:list",
|
|
"meta": {"title": "字典管理", "icon": "carbon:book"},
|
|
},
|
|
{
|
|
"id": LOG_MENU_ID,
|
|
"name": "SysLog",
|
|
"type": MenuTypeEnum.MENU.value,
|
|
"path": "/system/log",
|
|
"component": "/system/log/list",
|
|
"sort": 7,
|
|
"parent_id": SYSTEM_MENU_ID,
|
|
"auth_code": "system:log:list",
|
|
"meta": {"title": "日志管理", "icon": "carbon:cloud-logging"},
|
|
},
|
|
{
|
|
"id": "c5d1be767bce409bafa141ec8e5fc419",
|
|
"name": "SystemUserCreate",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 0,
|
|
"parent_id": USER_MENU_ID,
|
|
"auth_code": "system:user:create",
|
|
"meta": {"title": "common.create", "order": 0},
|
|
},
|
|
{
|
|
"id": "899b280630334766b01ff83f6f4ebacc",
|
|
"name": "SystemUserUpdate",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 1,
|
|
"parent_id": USER_MENU_ID,
|
|
"auth_code": "system:user:edit",
|
|
"meta": {"title": "common.edit"},
|
|
},
|
|
{
|
|
"id": "2431b03462a84f90ba15c29bca07d39e",
|
|
"name": "SystemUserDelete",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 2,
|
|
"parent_id": USER_MENU_ID,
|
|
"auth_code": "system:user:delete",
|
|
"meta": {"title": "common.delete"},
|
|
},
|
|
{
|
|
"id": "12cf74c410d044d986840c93fb70c397",
|
|
"name": "SystemUserResetPassword",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 3,
|
|
"parent_id": USER_MENU_ID,
|
|
"auth_code": "system:user:resetpwd",
|
|
"meta": {"title": "修改密码", "order": 3},
|
|
},
|
|
{
|
|
"id": "9f71686949c7410ea032956c52252a06",
|
|
"name": "SystemRoleCreate",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 0,
|
|
"parent_id": ROLE_MENU_ID,
|
|
"auth_code": "system:role:create",
|
|
"meta": {"title": "common.create", "order": 0},
|
|
},
|
|
{
|
|
"id": "bb271c537c604ee894a0339ced1b4d46",
|
|
"name": "SystemRoleEdit",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 1,
|
|
"parent_id": ROLE_MENU_ID,
|
|
"auth_code": "system:role:edit",
|
|
"meta": {"title": "common.edit", "order": 1},
|
|
},
|
|
{
|
|
"id": "a643f56b9a844c1eb8af7da1bd8e96da",
|
|
"name": "SystemRoleDelete",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 2,
|
|
"parent_id": ROLE_MENU_ID,
|
|
"auth_code": "system:role:delete",
|
|
"meta": {"title": "common.delete", "order": 2},
|
|
},
|
|
{
|
|
"id": "7f2913a04e1b47c8bc590eee4708a147",
|
|
"name": "SystemDeptCreate",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 0,
|
|
"parent_id": DEPT_MENU_ID,
|
|
"auth_code": "system:dept:create",
|
|
"meta": {"title": "common.create", "order": 0},
|
|
},
|
|
{
|
|
"id": "3e6e8ebda98c4e1aad27478d7bac595a",
|
|
"name": "SystemDeptEdit",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 1,
|
|
"parent_id": DEPT_MENU_ID,
|
|
"auth_code": "system:dept:edit",
|
|
"meta": {"title": "common.edit", "order": 1},
|
|
},
|
|
{
|
|
"id": "b52bb4045a434253ab0af21d03603458",
|
|
"name": "SystemDeptDelete",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 2,
|
|
"parent_id": DEPT_MENU_ID,
|
|
"auth_code": "system:dept:delete",
|
|
"meta": {"title": "common.delete", "order": 2},
|
|
},
|
|
{
|
|
"id": "18a8a2fcc8704c94baf47590dd7eb2e8",
|
|
"name": "SystemMenuCreate",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": None,
|
|
"sort": 0,
|
|
"parent_id": MENU_MENU_ID,
|
|
"auth_code": "system:menu:create",
|
|
"meta": {"title": "common.create"},
|
|
},
|
|
{
|
|
"id": "b41da6285e3f4bc4a39aa8ae13944b41",
|
|
"name": "SystemMenuEdit",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 1,
|
|
"parent_id": MENU_MENU_ID,
|
|
"auth_code": "system:menu:edit",
|
|
"meta": {"title": "common.edit", "order": 1},
|
|
},
|
|
{
|
|
"id": "a322ddada8ed4bcca1f5edcd9f3d33d0",
|
|
"name": "SystemMenuDelete",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 2,
|
|
"parent_id": MENU_MENU_ID,
|
|
"auth_code": "system:menu:delete",
|
|
"meta": {"title": "common.delete"},
|
|
},
|
|
{
|
|
"id": "57daf457de6546ab9e887233892e712e",
|
|
"name": "SystemConfigCreate",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 0,
|
|
"parent_id": CONFIG_MENU_ID,
|
|
"auth_code": "system:config:create",
|
|
"meta": {"title": "common.create", "order": 0},
|
|
},
|
|
{
|
|
"id": "5dc4a3d79f20496d82bc85f6eed1389b",
|
|
"name": "SystemConfigEdit",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 1,
|
|
"parent_id": CONFIG_MENU_ID,
|
|
"auth_code": "system:config:edit",
|
|
"meta": {"title": "common.edit", "order": 1},
|
|
},
|
|
{
|
|
"id": "bafe03a1da6c4224b69ecadd721cba0a",
|
|
"name": "SystemConfigDelete",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 2,
|
|
"parent_id": CONFIG_MENU_ID,
|
|
"auth_code": "system:config:delete",
|
|
"meta": {"title": "common.delete", "order": 2},
|
|
},
|
|
{
|
|
"id": "8c96ce0db0724139a9ab7fbcfcf52500",
|
|
"name": "SystemDictCreate",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 0,
|
|
"parent_id": DICT_MENU_ID,
|
|
"auth_code": "system:dict:create",
|
|
"meta": {"title": "common.create", "order": 0},
|
|
},
|
|
{
|
|
"id": "de5bcbdb81b34b02991614c13f12043a",
|
|
"name": "SystemDictEdit",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 1,
|
|
"parent_id": DICT_MENU_ID,
|
|
"auth_code": "system:dict:edit",
|
|
"meta": {"title": "common.edit", "order": 1},
|
|
},
|
|
{
|
|
"id": "3385698f84e44249ad5eb733d7232c96",
|
|
"name": "SystemDictDelete",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 2,
|
|
"parent_id": DICT_MENU_ID,
|
|
"auth_code": "system:dict:delete",
|
|
"meta": {"title": "common.delete", "order": 2},
|
|
},
|
|
{
|
|
"id": "74e4cff0de2b4532a187ed01714d6577",
|
|
"name": "SystemLogDelete",
|
|
"type": MenuTypeEnum.BUTTON.value,
|
|
"path": "",
|
|
"sort": 0,
|
|
"parent_id": LOG_MENU_ID,
|
|
"auth_code": "system:log:delete",
|
|
"meta": {"title": "common.delete", "order": 0},
|
|
},
|
|
]
|
|
|
|
DEFAULT_DICT_TYPES = [
|
|
{
|
|
"type_name": "状态",
|
|
"type_code": "status",
|
|
"desc": "通用启停状态",
|
|
"sort": 1,
|
|
"data": [
|
|
{"label": "启用", "code": "enabled", "value": "enabled", "sort": 1},
|
|
{"label": "停用", "code": "disabled", "value": "disabled", "sort": 2},
|
|
],
|
|
},
|
|
{
|
|
"type_name": "性别",
|
|
"type_code": "gender",
|
|
"desc": "用户性别",
|
|
"sort": 2,
|
|
"data": [
|
|
{"label": "男", "code": "male", "value": "male", "sort": 1},
|
|
{"label": "女", "code": "female", "value": "female", "sort": 2},
|
|
{"label": "保密", "code": "secure", "value": "secure", "sort": 3},
|
|
],
|
|
},
|
|
]
|
|
|
|
DEFAULT_CONFIGS = [
|
|
{
|
|
"type": SysConfigType.USER.value,
|
|
"name": "默认用户密码",
|
|
"code": "DEFAULT_USER_PASSWORD",
|
|
"value": "123456",
|
|
"desc": "系统自动注册时使用的默认用户密码",
|
|
"sort": 1,
|
|
},
|
|
{
|
|
"type": SysConfigType.USER.value,
|
|
"name": "默认用户角色",
|
|
"code": "DEFAULT_USER_ROLES",
|
|
"value": "COMMON",
|
|
"desc": "系统自动注册时使用的默认用户角色,多个角色用逗号分隔",
|
|
"sort": 2,
|
|
},
|
|
{
|
|
"type": SysConfigType.USER.value,
|
|
"name": "默认用户部门",
|
|
"code": "DEFAULT_USER_DEPTS",
|
|
"value": "",
|
|
"desc": "系统自动注册时使用的默认用户部门,多个部门用逗号分隔",
|
|
"sort": 3,
|
|
},
|
|
{
|
|
"type": SysConfigType.SYSTEM.value,
|
|
"name": "系统名称",
|
|
"code": "system.name",
|
|
"value": "iTi-Flask",
|
|
"desc": "默认系统名称",
|
|
"sort": 10,
|
|
},
|
|
{
|
|
"type": SysConfigType.SYSTEM.value,
|
|
"name": "后端访问地址",
|
|
"code": "BACKEND_URL",
|
|
"value": "http://localhost:5000",
|
|
"desc": "后端访问地址。应配置为前端可访问的后端地址",
|
|
"sort": 90,
|
|
},
|
|
{
|
|
"type": SysConfigType.SYSTEM.value,
|
|
"name": "文件回收站功能",
|
|
"code": "FILE_RECYCLE_ENABLED",
|
|
"value": "true",
|
|
"desc": "是否启用文件回收站功能",
|
|
"sort": 100,
|
|
},
|
|
{
|
|
"type": SysConfigType.SYSTEM.value,
|
|
"name": "回收站保留天数",
|
|
"code": "FILE_RECYCLE_DAYS",
|
|
"value": "30",
|
|
"desc": "回收站文件保留天数",
|
|
"sort": 101,
|
|
},
|
|
{
|
|
"type": SysConfigType.SYSTEM.value,
|
|
"name": "文件分享功能",
|
|
"code": "FILE_SHARE_ENABLED",
|
|
"value": "true",
|
|
"desc": "是否启用文件分享功能",
|
|
"sort": 102,
|
|
},
|
|
{
|
|
"type": SysConfigType.SYSTEM.value,
|
|
"name": "分享默认过期时间",
|
|
"code": "FILE_SHARE_DEFAULT_EXPIRE_HOURS",
|
|
"value": "168",
|
|
"desc": "文件分享默认过期时间(小时)",
|
|
"sort": 103,
|
|
},
|
|
{
|
|
"type": SysConfigType.SYSTEM.value,
|
|
"name": "分片上传阈值",
|
|
"code": "FILE_CHUNK_THRESHOLD",
|
|
"value": "104857600",
|
|
"desc": "文件大小超过此阈值时使用分片上传",
|
|
"sort": 104,
|
|
},
|
|
{
|
|
"type": SysConfigType.SYSTEM.value,
|
|
"name": "分片上传分片大小",
|
|
"code": "FILE_CHUNK_SIZE",
|
|
"value": "2097152",
|
|
"desc": "分片上传时每个分片的大小(字节)",
|
|
"sort": 105,
|
|
},
|
|
]
|
|
|
|
ROLE_MENU_BINDINGS = {
|
|
"ADMIN": [item["id"] for item in DEFAULT_MENUS],
|
|
"COMMON": [
|
|
SYSTEM_MENU_ID,
|
|
USER_MENU_ID,
|
|
ROLE_MENU_ID,
|
|
DEPT_MENU_ID,
|
|
MENU_MENU_ID,
|
|
CONFIG_MENU_ID,
|
|
DICT_MENU_ID,
|
|
],
|
|
}
|
|
|
|
def seed_system_data(
|
|
module_registry: ModuleRegistry | None = None,
|
|
) -> dict[str, dict[str, int]]:
|
|
counters = {
|
|
"roles": _seed_roles(),
|
|
"menus": _seed_menus(),
|
|
"module_menus": _seed_module_menus(module_registry),
|
|
"dicts": _seed_dicts(),
|
|
"configs": _seed_configs(),
|
|
"users": _seed_users(),
|
|
"user_roles": _seed_user_roles(),
|
|
"role_menus": _seed_role_menus(),
|
|
"module_role_menus": _seed_module_role_menus(module_registry),
|
|
}
|
|
db.session.commit()
|
|
return {name: counter.as_dict() for name, counter in counters.items()}
|
|
|
|
|
|
def _seed_roles() -> SeedCounter:
|
|
counter = SeedCounter()
|
|
for item in DEFAULT_ROLES:
|
|
role = db.session.scalar(select(Role).filter_by(code=item["code"]))
|
|
payload = dict(item)
|
|
payload.setdefault("status", StatusEnum.ENABLED.value)
|
|
if role is None:
|
|
db.session.add(Role(**_audit_safe(payload)))
|
|
counter.created += 1
|
|
continue
|
|
changed = _assign_if_changed(role, payload)
|
|
counter.updated += 1 if changed else 0
|
|
counter.skipped += 0 if changed else 1
|
|
return counter
|
|
|
|
|
|
def _seed_menus() -> SeedCounter:
|
|
counter = SeedCounter()
|
|
for item in DEFAULT_MENUS:
|
|
_seed_menu_payload(counter, item)
|
|
return counter
|
|
|
|
|
|
def _seed_module_menus(module_registry: ModuleRegistry | None) -> SeedCounter:
|
|
counter = SeedCounter()
|
|
for menu_seed in _module_menu_seeds(module_registry):
|
|
_seed_menu_payload(counter, menu_seed.as_menu_payload())
|
|
return counter
|
|
|
|
|
|
def _seed_menu_payload(counter: SeedCounter, item: dict[str, Any]) -> None:
|
|
menu = db.session.scalar(select(SysMenu).filter_by(id=item["id"]))
|
|
payload = dict(item)
|
|
payload.setdefault("status", StatusEnum.ENABLED.value)
|
|
if menu is None:
|
|
db.session.add(SysMenu(**payload))
|
|
counter.created += 1
|
|
return
|
|
changed = _assign_if_changed(menu, payload)
|
|
counter.updated += 1 if changed else 0
|
|
counter.skipped += 0 if changed else 1
|
|
|
|
|
|
def _seed_dicts() -> SeedCounter:
|
|
counter = SeedCounter()
|
|
for item in DEFAULT_DICT_TYPES:
|
|
data_items = item["data"]
|
|
if not isinstance(data_items, Iterable):
|
|
data_items = []
|
|
dict_type = db.session.scalar(
|
|
select(SysDictType).filter_by(type_code=item["type_code"])
|
|
)
|
|
payload = {key: value for key, value in item.items() if key != "data"}
|
|
payload.setdefault("status", StatusEnum.ENABLED.value)
|
|
if dict_type is None:
|
|
db.session.add(SysDictType(**_audit_safe(payload)))
|
|
counter.created += 1
|
|
else:
|
|
changed = _assign_if_changed(dict_type, payload)
|
|
counter.updated += 1 if changed else 0
|
|
counter.skipped += 0 if changed else 1
|
|
|
|
for data in data_items:
|
|
dict_data = db.session.scalar(
|
|
select(SysDictData).filter_by(
|
|
type_code=item["type_code"], code=data["code"]
|
|
)
|
|
)
|
|
data_payload = dict(data)
|
|
data_payload["type_code"] = item["type_code"]
|
|
data_payload.setdefault("status", StatusEnum.ENABLED.value)
|
|
if dict_data is None:
|
|
db.session.add(SysDictData(**_audit_safe(data_payload)))
|
|
counter.created += 1
|
|
else:
|
|
changed = _assign_if_changed(dict_data, data_payload)
|
|
counter.updated += 1 if changed else 0
|
|
counter.skipped += 0 if changed else 1
|
|
return counter
|
|
|
|
|
|
def _seed_configs() -> SeedCounter:
|
|
counter = SeedCounter()
|
|
for item in DEFAULT_CONFIGS:
|
|
config = db.session.scalar(
|
|
select(SysConfig).filter_by(type=item["type"], code=item["code"])
|
|
)
|
|
payload = dict(item)
|
|
payload.setdefault("status", StatusEnum.ENABLED.value)
|
|
if config is None:
|
|
db.session.add(SysConfig(**_audit_safe(payload)))
|
|
counter.created += 1
|
|
continue
|
|
changed = _assign_if_changed(config, payload)
|
|
counter.updated += 1 if changed else 0
|
|
counter.skipped += 0 if changed else 1
|
|
return counter
|
|
|
|
|
|
def _seed_users() -> SeedCounter:
|
|
counter = SeedCounter()
|
|
for item in DEFAULT_USERS:
|
|
user = db.session.scalar(select(User).filter_by(username=item["username"]))
|
|
payload = {key: value for key, value in item.items() if key != "role_codes"}
|
|
if user is None:
|
|
user = User(status=StatusEnum.ENABLED.value, **_audit_safe(payload))
|
|
db.session.add(user)
|
|
counter.created += 1
|
|
continue
|
|
counter.skipped += 1
|
|
return counter
|
|
|
|
|
|
def _seed_user_roles() -> SeedCounter:
|
|
counter = SeedCounter()
|
|
for item in _default_user_role_bindings():
|
|
user = db.session.scalar(select(User).filter_by(username=item["username"]))
|
|
if user is None:
|
|
counter.skipped += len(item["role_codes"])
|
|
continue
|
|
existing_codes = {role.code for role in user.roles}
|
|
for role_code in item["role_codes"]:
|
|
if role_code in existing_codes:
|
|
counter.skipped += 1
|
|
continue
|
|
role = db.session.scalar(select(Role).filter_by(code=role_code))
|
|
if role is None:
|
|
counter.skipped += 1
|
|
continue
|
|
user.roles.append(role)
|
|
counter.created += 1
|
|
return counter
|
|
|
|
|
|
def _seed_role_menus() -> SeedCounter:
|
|
counter = SeedCounter()
|
|
for role_code, menu_ids in _default_role_menu_bindings():
|
|
role = db.session.scalar(select(Role).filter_by(code=role_code))
|
|
if role is None:
|
|
counter.skipped += len(menu_ids)
|
|
continue
|
|
existing_ids = {menu.id for menu in role.menus}
|
|
for menu_id in menu_ids:
|
|
if menu_id in existing_ids:
|
|
counter.skipped += 1
|
|
continue
|
|
menu = db.session.scalar(select(SysMenu).filter_by(id=menu_id))
|
|
if menu is None:
|
|
counter.skipped += 1
|
|
continue
|
|
role.menus.append(menu)
|
|
counter.created += 1
|
|
return counter
|
|
|
|
|
|
def _default_user_role_bindings() -> list[dict[str, Any]]:
|
|
return [
|
|
{"username": item["username"], "role_codes": item["role_codes"]}
|
|
for item in DEFAULT_USERS
|
|
]
|
|
|
|
|
|
def _default_role_menu_bindings() -> list[tuple[str, list[str]]]:
|
|
return list(ROLE_MENU_BINDINGS.items())
|
|
|
|
|
|
def _seed_module_role_menus(module_registry: ModuleRegistry | None) -> SeedCounter:
|
|
counter = SeedCounter()
|
|
for menu_seed, role_code in _module_role_menu_bindings(module_registry):
|
|
role = db.session.scalar(select(Role).filter_by(code=role_code))
|
|
menu = db.session.scalar(select(SysMenu).filter_by(id=menu_seed.id))
|
|
if role is None or menu is None:
|
|
counter.skipped += 1
|
|
continue
|
|
if menu.id in {item.id for item in role.menus}:
|
|
counter.skipped += 1
|
|
continue
|
|
role.menus.append(menu)
|
|
counter.created += 1
|
|
return counter
|
|
|
|
|
|
def _module_role_menu_bindings(
|
|
module_registry: ModuleRegistry | None,
|
|
) -> list[tuple[ModuleMenuSeed, str]]:
|
|
return [
|
|
(menu_seed, role_code)
|
|
for menu_seed in _module_menu_seeds(module_registry)
|
|
for role_code in menu_seed.admin_roles
|
|
]
|
|
|
|
|
|
def _module_menu_seeds(
|
|
module_registry: ModuleRegistry | None,
|
|
) -> list[ModuleMenuSeed]:
|
|
if module_registry is None:
|
|
return []
|
|
return module_registry.list_menu_seeds()
|
|
|
|
|
|
def _assign_if_changed(model: Any, values: dict) -> bool:
|
|
changed = False
|
|
for key, value in values.items():
|
|
if getattr(model, key) != value:
|
|
setattr(model, key, value)
|
|
changed = True
|
|
return changed
|
|
|
|
|
|
def _audit_safe(values: dict) -> dict:
|
|
payload = dict(values)
|
|
payload.setdefault("created_by", None)
|
|
payload.setdefault("updated_by", None)
|
|
return payload
|