hr-system/apps/hr_permission.py

246 lines
13 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
"""hr-system 权限与数据范围底座F11 / T08"""
import json, time, uuid
from apppublic import log
from sqlor import Db
SCOPE_TYPE_ORG = "org"
SCOPE_TYPE_FIELD = "field"
ROLE_EMPLOYEE = "employee"
ROLE_MANAGER = "manager"
ROLE_HR_ADMIN = "hr_admin"
ROLE_SYS_ADMIN = "sys_admin"
ROLE_ADMIN = "admin"
BUILTIN_ROLES = (ROLE_EMPLOYEE, ROLE_MANAGER, ROLE_HR_ADMIN, ROLE_SYS_ADMIN)
_db = None
def _get_db():
global _db
if _db is None:
_db = Db("hrs")
return _db
def _now():
return time.strftime("%Y-%m-%d %H:%M:%S")
def _uuid():
return uuid.uuid4().hex
# ---- 角色 ----
def role_list(req):
db = _get_db()
rows = db.query("SELECT r.id, r.role_code, r.role_name, r.remark, r.created_at, (SELECT COUNT(*) FROM sys_role_permission rp WHERE rp.role_id = r.id) AS perm_count FROM sys_role r ORDER BY r.created_at")
return {"code": 0, "data": rows}
def role_detail(req):
role_id = req.get("id") or req.get("role_id")
if not role_id: return {"code": 1, "msg": "缺少角色 id"}
db = _get_db()
role = db.query_one("SELECT * FROM sys_role WHERE id = %s", (role_id,))
if not role: return {"code": 1, "msg": "角色不存在"}
perms = db.query("SELECT perm_id FROM sys_role_permission WHERE role_id = %s", (role_id,))
role["perm_ids"] = [p["perm_id"] for p in perms]
return {"code": 0, "data": role}
def role_create(req):
db = _get_db()
role_code = (req.get("role_code") or "").strip()
role_name = (req.get("role_name") or "").strip()
if not role_code or not role_name: return {"code": 1, "msg": "角色编码与名称必填"}
if db.query_one("SELECT id FROM sys_role WHERE role_code = %s", (role_code,)):
return {"code": 1, "msg": "角色编码已存在"}
rid = _uuid()
db.execute("INSERT INTO sys_role (id, role_code, role_name, remark, created_by, created_at, updated_at) VALUES (%s,%s,%s,%s,%s,%s,%s)", (rid, role_code, role_name, req.get("remark",""), req.get("operator_id",""), _now(), _now()))
return {"code": 0, "data": {"id": rid}}
def role_update(req):
role_id = req.get("id") or req.get("role_id")
if not role_id: return {"code": 1, "msg": "缺少角色 id"}
db = _get_db()
db.execute("UPDATE sys_role SET role_name=%s, remark=%s, updated_by=%s, updated_at=%s WHERE id=%s", (req.get("role_name",""), req.get("remark",""), req.get("operator_id",""), _now(), role_id))
return {"code": 0}
def role_delete(req):
role_id = req.get("id") or req.get("role_id")
if not role_id: return {"code": 1, "msg": "缺少角色 id"}
db = _get_db()
role = db.query_one("SELECT role_code FROM sys_role WHERE id = %s", (role_id,))
if not role: return {"code": 1, "msg": "角色不存在"}
if role["role_code"] in BUILTIN_ROLES or role["role_code"] == ROLE_ADMIN:
return {"code": 1, "msg": "内置角色禁止删除"}
db.execute("DELETE FROM sys_role_permission WHERE role_id = %s", (role_id,))
db.execute("DELETE FROM sys_user_role WHERE role_id = %s", (role_id,))
db.execute("DELETE FROM sys_role WHERE id = %s", (role_id,))
return {"code": 0}
def role_assign_perms(req):
role_id = req.get("role_id") or req.get("id")
if not role_id: return {"code": 1, "msg": "缺少角色 id"}
perm_ids = req.get("perm_ids") or []
db = _get_db()
if not db.query_one("SELECT id FROM sys_role WHERE id = %s", (role_id,)):
return {"code": 1, "msg": "角色不存在"}
db.execute("DELETE FROM sys_role_permission WHERE role_id = %s", (role_id,))
if perm_ids:
db.executemany("INSERT INTO sys_role_permission (role_id, perm_id) VALUES (%s, %s)", [(role_id, p) for p in perm_ids])
return {"code": 0, "data": {"count": len(perm_ids)}}
# ---- 管理员 ----
def admin_list(req):
db = _get_db()
rows = db.query("SELECT u.id, u.username, u.real_name, u.status, u.created_at, (SELECT GROUP_CONCAT(r.role_code) FROM sys_user_role ur JOIN sys_role r ON r.id=ur.role_id WHERE ur.user_id=u.id) AS role_codes FROM sys_user u ORDER BY u.created_at")
return {"code": 0, "data": rows}
def admin_create(req):
db = _get_db()
username = (req.get("username") or "").strip()
if not username: return {"code": 1, "msg": "用户名必填"}
if db.query_one("SELECT id FROM sys_user WHERE username = %s", (username,)):
return {"code": 1, "msg": "用户名已存在"}
uid = _uuid()
db.execute("INSERT INTO sys_user (id, username, real_name, password, status, created_at, updated_at) VALUES (%s,%s,%s,%s,%s,%s,%s)", (uid, username, req.get("real_name",""), req.get("password",""), req.get("status",1), _now(), _now()))
role_ids = req.get("role_ids") or []
if role_ids:
db.executemany("INSERT INTO sys_user_role (user_id, role_id) VALUES (%s, %s)", [(uid, r) for r in role_ids])
return {"code": 0, "data": {"id": uid}}
def admin_bind_roles(req):
user_id = req.get("user_id") or req.get("id")
if not user_id: return {"code": 1, "msg": "缺少用户 id"}
role_ids = req.get("role_ids") or []
db = _get_db()
db.execute("DELETE FROM sys_user_role WHERE user_id = %s", (user_id,))
if role_ids:
db.executemany("INSERT INTO sys_user_role (user_id, role_id) VALUES (%s, %s)", [(user_id, r) for r in role_ids])
return {"code": 0}
def admin_disable(req):
user_id = req.get("user_id") or req.get("id")
if not user_id: return {"code": 1, "msg": "缺少用户 id"}
db = _get_db()
db.execute("UPDATE sys_user SET status=%s, updated_at=%s WHERE id=%s", (req.get("status",0), _now(), user_id))
return {"code": 0}
# ---- 数据范围 ----
def _json_loads(raw, default):
if not raw: return default
try: return json.loads(raw)
except (TypeError, ValueError): return default
def scope_list(req):
db = _get_db()
rows = db.query("SELECT s.*, u.username, u.real_name FROM sys_data_scope s LEFT JOIN sys_user u ON u.id = s.admin_user_id ORDER BY s.created_at")
for r in rows:
r["org_ids"] = _json_loads(r.get("org_ids_json"), [])
r["field_ids"] = _json_loads(r.get("field_ids_json"), [])
return {"code": 0, "data": rows}
def scope_save(req):
db = _get_db()
admin_user_id = req.get("admin_user_id") or req.get("user_id")
if not admin_user_id: return {"code": 1, "msg": "缺少管理员用户"}
scope_type = req.get("scope_type") or SCOPE_TYPE_ORG
org_json = json.dumps(req.get("org_ids") or [], ensure_ascii=False)
field_json = json.dumps(req.get("field_ids") or [], ensure_ascii=False)
exists = db.query_one("SELECT id FROM sys_data_scope WHERE admin_user_id = %s", (admin_user_id,))
if exists:
db.execute("UPDATE sys_data_scope SET scope_type=%s, org_ids_json=%s, field_ids_json=%s, remark=%s, updated_by=%s, updated_at=%s WHERE id=%s", (scope_type, org_json, field_json, req.get("remark",""), req.get("operator_id",""), _now(), exists["id"]))
return {"code": 0, "data": {"id": exists["id"]}}
sid = _uuid()
db.execute("INSERT INTO sys_data_scope (id, admin_user_id, scope_type, org_ids_json, field_ids_json, remark, created_by, updated_by, created_at, updated_at) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", (sid, admin_user_id, scope_type, org_json, field_json, req.get("remark",""), req.get("operator_id",""), req.get("operator_id",""), _now(), _now()))
return {"code": 0, "data": {"id": sid}}
def scope_delete(req):
scope_id = req.get("id")
if not scope_id: return {"code": 1, "msg": "缺少配置 id"}
db = _get_db()
db.execute("DELETE FROM sys_data_scope WHERE id = %s", (scope_id,))
return {"code": 0}
# ---- 叠加机制 ----
def _expand_org_tree(db, org_ids):
if not org_ids: return []
result = set(org_ids); frontier = list(org_ids); seen = set(org_ids)
while frontier:
ph = ",".join(["%s"] * len(frontier))
children = db.query("SELECT id FROM org_unit WHERE parent_id IN (%s)" % ph, frontier)
frontier = []
for c in children:
if c["id"] not in seen:
seen.add(c["id"]); result.add(c["id"]); frontier.append(c["id"])
return sorted(result)
def get_data_scope(user_id):
db = _get_db()
roles = db.query("SELECT r.role_code FROM sys_user_role ur JOIN sys_role r ON r.id = ur.role_id WHERE ur.user_id = %s", (user_id,))
role_codes = [r["role_code"] for r in roles]
result = {"org_all": False, "org_ids": [], "field_all": False, "field_ids": [], "role_codes": role_codes}
if ROLE_SYS_ADMIN in role_codes or ROLE_ADMIN in role_codes:
result["org_all"] = True; result["field_all"] = True
return result
scope_rows = db.query("SELECT scope_type, org_ids_json, field_ids_json FROM sys_data_scope WHERE admin_user_id = %s", (user_id,))
if not scope_rows: return result
org_union = set(); field_union = set(); field_restricted = False
for row in scope_rows:
st = row.get("scope_type") or ""
oids = _json_loads(row.get("org_ids_json"), [])
fids = _json_loads(row.get("field_ids_json"), [])
if st in (SCOPE_TYPE_ORG, "all") and oids: org_union.update(oids)
if st in (SCOPE_TYPE_FIELD, "all"):
field_restricted = True; field_union.update(fids)
result["org_ids"] = _expand_org_tree(db, sorted(org_union))
if field_restricted: result["field_ids"] = sorted(field_union)
else: result["field_all"] = True
return result
def scope_query(req):
user_id = req.get("user_id") or req.get("operator_id") or req.get("uid")
if not user_id: return {"code": 1, "msg": "缺少 user_id"}
return {"code": 0, "data": get_data_scope(user_id)}
# ---- 初始化 ----
def init_permission(db=None):
db = db or _get_db()
now = _now()
counts = {"roles": 0, "users": 0, "perms": 0}
roles = [(ROLE_EMPLOYEE,"员工自助","员工本人查看/修改个人档案、发起自助申请"),(ROLE_MANAGER,"经理","管理本部门员工、发起并审批本部门人事异动"),(ROLE_HR_ADMIN,"HR管理员","管理全公司人事业务,受数据范围约束"),(ROLE_SYS_ADMIN,"系统管理员","系统配置、角色/管理员/数据范围/审计管理")]
role_id_map = {}
for code, name, remark in roles:
row = db.query_one("SELECT id FROM sys_role WHERE role_code = %s", (code,))
if not row:
rid = _uuid()
db.execute("INSERT INTO sys_role (id, role_code, role_name, remark, created_by, created_at, updated_at) VALUES (%s,%s,%s,%s,%s,%s,%s)", (rid, code, name, remark, "system", now, now))
counts["roles"] += 1
else: rid = row["id"]
role_id_map[code] = rid
admin_row = db.query_one("SELECT id FROM sys_user WHERE username = 'admin'")
if not admin_row:
uid = _uuid()
db.execute("INSERT INTO sys_user (id, username, real_name, password, status, created_at, updated_at) VALUES (%s,%s,%s,%s,%s,%s,%s)", (uid, "admin", "系统管理员", "", 1, now, now))
counts["users"] += 1
else: uid = admin_row["id"]
for code, rid in role_id_map.items():
if not db.query_one("SELECT 1 AS x FROM sys_user_role WHERE user_id = %s AND role_id = %s", (uid, rid)):
db.execute("INSERT INTO sys_user_role (user_id, role_id) VALUES (%s, %s)", (uid, rid))
base_perms = [("hr_system:role_admin","角色权限配置","/hr_system/role_admin"),("hr_system:data_scope","数据范围配置","/hr_system/data_scope"),("hr_system:audit_log","操作日志查询","/hr_system/audit_log")]
perm_id_map = {}
for code, name, path in base_perms:
row = db.query_one("SELECT id FROM sys_permission WHERE perm_code = %s", (code,))
if not row:
pid = _uuid()
db.execute("INSERT INTO sys_permission (id, perm_code, perm_name, perm_path, created_at) VALUES (%s,%s,%s,%s,%s)", (pid, code, name, path, now))
counts["perms"] += 1
else: pid = row["id"]
perm_id_map[code] = pid
for pid in perm_id_map.values():
if not db.query_one("SELECT 1 AS x FROM sys_role_permission WHERE role_id = %s AND perm_id = %s", (role_id_map[ROLE_SYS_ADMIN], pid)):
db.execute("INSERT INTO sys_role_permission (role_id, perm_id) VALUES (%s, %s)", (role_id_map[ROLE_SYS_ADMIN], pid))
return counts
ENDPOINTS = {"role_list":role_list,"role_detail":role_detail,"role_create":role_create,"role_update":role_update,"role_delete":role_delete,"role_assign_perms":role_assign_perms,"admin_list":admin_list,"admin_create":admin_create,"admin_bind_roles":admin_bind_roles,"admin_disable":admin_disable,"scope_list":scope_list,"scope_save":scope_save,"scope_delete":scope_delete,"scope_query":scope_query}
def register(server_env):
server_env.register_public("get_data_scope", get_data_scope)
server_env.register_api(ENDPOINTS)
log.info("hr-system 权限底座已注册get_data_scope + %d 个端点", len(ENDPOINTS))