From 52cd71f861ffda6a0c2fd0ae1da42177fe5d26c5 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Thu, 11 Jun 2026 16:57:04 +0800 Subject: [PATCH] feat: add user_status check on login, enable/disable toolbar, fix editexclouded for add user --- json/users.json | 24 ++++++++++++++++++++++-- rbac/check_perm.py | 10 ++++++++++ wwwroot/users/disable_user.dspy | 8 ++++++++ wwwroot/users/enable_user.dspy | 8 ++++++++ 4 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 wwwroot/users/disable_user.dspy create mode 100644 wwwroot/users/enable_user.dspy diff --git a/json/users.json b/json/users.json index f55b5d6..c0f9a3f 100644 --- a/json/users.json +++ b/json/users.json @@ -9,8 +9,28 @@ "exclouded": ["id", "password", "orgid", "nick_name" ], "cwidth": {} }, - "editexclouded": [ - "id", "nick_name", "orgid", "last_login_fail", "last_login", "sync_from" + "editexclouded": ["id", "nick_name", "orgid", "last_login_fail", "last_login", "sync_from", "login_fail_count", "created_at"], + "record_toolbar": [ + { + "label": "启用", + "actiontype": "dspy", + "url": "/rbac/users/enable_user.dspy", + "options": { + "icon": "check", + "cwidth": 16, + "cheight": 9 + } + }, + { + "label": "禁用", + "actiontype": "dspy", + "url": "/rbac/users/disable_user.dspy", + "options": { + "icon": "block", + "cwidth": 16, + "cheight": 9 + } + } ], "subtables": [ { diff --git a/rbac/check_perm.py b/rbac/check_perm.py index c3dace4..d584b5d 100644 --- a/rbac/check_perm.py +++ b/rbac/check_perm.py @@ -158,6 +158,11 @@ async def checkUserPassword(request, username, password): return False user = recs[0] + # Check user status (disabled) + user_status = getattr(user, 'user_status', '0') or '0' + if user_status != '0': + debug(f'User {username} is disabled (status={user_status})') + return False fail_count = getattr(user, 'login_fail_count', 0) or 0 last_fail = getattr(user, 'last_login_fail', None) @@ -209,6 +214,11 @@ async def basic_auth(sor, request): return None # Check lockout in Python layer (DB-agnostic) user = recs[0] + # Check user status (disabled) + user_status = getattr(user, 'user_status', '0') or '0' + if user_status != '0': + debug(f'User {username} is disabled (status={user_status}) via basic auth') + return None fail_count = getattr(user, 'login_fail_count', 0) or 0 last_fail = getattr(user, 'last_login_fail', None) if _is_locked(fail_count, last_fail): diff --git a/wwwroot/users/disable_user.dspy b/wwwroot/users/disable_user.dspy new file mode 100644 index 0000000..3f6f2cc --- /dev/null +++ b/wwwroot/users/disable_user.dspy @@ -0,0 +1,8 @@ +if not params_kw.get('id'): + return {"widgettype":"Error","options":{"title":"Error","message":"no user selected","cwidth":16,"cheight":9,"timeout":3}} + +dbname = get_module_dbname('rbac') +db = DBPools() +async with db.sqlorContext(dbname) as sor: + await sor.U('users', {'id': params_kw.id, 'user_status': '1'}) + return {"widgettype":"Message","options":{"title":"Success","message":"user disabled","cwidth":16,"cheight":9,"timeout":3}} diff --git a/wwwroot/users/enable_user.dspy b/wwwroot/users/enable_user.dspy new file mode 100644 index 0000000..12b0497 --- /dev/null +++ b/wwwroot/users/enable_user.dspy @@ -0,0 +1,8 @@ +if not params_kw.get('id'): + return {"widgettype":"Error","options":{"title":"Error","message":"no user selected","cwidth":16,"cheight":9,"timeout":3}} + +dbname = get_module_dbname('rbac') +db = DBPools() +async with db.sqlorContext(dbname) as sor: + await sor.U('users', {'id': params_kw.id, 'user_status': '0', 'login_fail_count': 0}) + return {"widgettype":"Message","options":{"title":"Success","message":"user enabled","cwidth":16,"cheight":9,"timeout":3}}