diff --git a/i18n/en/msg.txt b/i18n/en/msg.txt index d24dc2b..b9fc89f 100644 --- a/i18n/en/msg.txt +++ b/i18n/en/msg.txt @@ -131,3 +131,7 @@ Cancel: Cancel 只读用户: Read-Only User 访问控制: Access Control 最后登录: Last Login +清除登录次数: Clear Login Fail Count +新密码: New Password +确认清除该用户的连续登录失败次数?: Clear the consecutive login failure count of this user? +为选中用户设置新密码(至少8位): Set a new password (at least 8 characters) for the selected user diff --git a/i18n/jp/msg.txt b/i18n/jp/msg.txt index 6f0af26..96e8f1f 100644 --- a/i18n/jp/msg.txt +++ b/i18n/jp/msg.txt @@ -131,3 +131,7 @@ Cancel: キャンセル 只读用户: 読み取り専用ユーザー 访问控制: アクセス制御 最后登录: 最終ログイン +清除登录次数: ログイン失敗回数をクリア +新密码: 新しいパスワード +确认清除该用户的连续登录失败次数?: このユーザーの連続ログイン失敗回数をクリアしますか? +为选中用户设置新密码(至少8位): 選択したユーザーに新しいパスワード(8文字以上)を設定 diff --git a/i18n/ko/msg.txt b/i18n/ko/msg.txt index 523f2e2..c4915ea 100644 --- a/i18n/ko/msg.txt +++ b/i18n/ko/msg.txt @@ -131,3 +131,7 @@ Cancel: 취소 只读用户: 읽기 전용 사용자 访问控制: 접근 제어 最后登录: 마지막 로그인 +清除登录次数: 로그인 실패 횟수 초기화 +新密码: 새 비밀번호 +确认清除该用户的连续登录失败次数?: 이 사용자의 연속 로그인 실패 횟수를 초기화하시겠습니까? +为选中用户设置新密码(至少8位): 선택한 사용자에게 새 비밀번호(8자 이상) 설정 diff --git a/i18n/zh/msg.txt b/i18n/zh/msg.txt index c0164cb..bec6cca 100644 --- a/i18n/zh/msg.txt +++ b/i18n/zh/msg.txt @@ -137,3 +137,7 @@ you are not owner user: you are not owner user 需输入验证码: 需输入验证码 验证失败: 验证失败 验证码: 验证码 +清除登录次数: 清除登录次数 +新密码: 新密码 +确认清除该用户的连续登录失败次数?: 确认清除该用户的连续登录失败次数? +为选中用户设置新密码(至少8位): 为选中用户设置新密码(至少8位) diff --git a/json/users.json b/json/users.json index b8711a6..1588e5a 100644 --- a/json/users.json +++ b/json/users.json @@ -52,36 +52,60 @@ } } ], - "binds": [ - { - "wid": "self", - "event": "enable_user", - "actiontype": "script", - "target": "self", - "script": "var tid=bricks.getWidgetById('users_tbl');var d=tid.select_row.user_data;fetch('/rbac/users/enable_user.dspy?id='+d.id,{method:'POST'}).then(function(r){return r.json()}).then(function(r){if(r.widgettype==='Message'){tid.render({})}else{bricks.show_error(r.options)}})" - }, - { - "wid": "self", - "event": "disable_user", - "actiontype": "script", - "target": "self", - "script": "var tid=bricks.getWidgetById('users_tbl');var d=tid.select_row.user_data;fetch('/rbac/users/disable_user.dspy?id='+d.id,{method:'POST'}).then(function(r){return r.json()}).then(function(r){if(r.widgettype==='Message'){tid.render({})}else{bricks.show_error(r.options)}})" - }, - { - "wid": "self", - "event": "reset_password", - "actiontype": "script", - "target": "self", - "script": "var tid=bricks.getWidgetById('users_tbl');var d=tid.select_row.user_data;var np=prompt('为用户 '+d.username+' 设置新密码(至少8位):');if(!np){return}var cp=prompt('再次输入以确认:');if(!cp){return}fetch('/rbac/api/admin_reset_password.dspy',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userid:d.id,new_password:np,cfm_password:cp})}).then(function(r){return r.json()}).then(function(r){if(r.widgettype==='Message'){bricks.show_message(r.options);tid.render({})}else{bricks.show_error(r.options)}})" - }, - { - "wid": "self", - "event": "clear_login_fail", - "actiontype": "script", - "target": "self", - "script": "var tid=bricks.getWidgetById('users_tbl');var d=tid.select_row.user_data;fetch('/rbac/api/clear_login_fail.dspy?id='+d.id,{method:'POST'}).then(function(r){return r.json()}).then(function(r){if(r.widgettype==='Message'){bricks.show_message(r.options);tid.render({})}else{bricks.show_error(r.options)}})" - } - ], + "binds": [ + { + "wid": "self", + "event": "enable_user", + "actiontype": "script", + "target": "self", + "script": "var tid=bricks.getWidgetById('users_tbl');var d=tid.select_row.user_data;fetch('/rbac/users/enable_user.dspy?id='+d.id,{method:'POST'}).then(function(r){return r.json()}).then(function(r){if(r.widgettype==='Message'){tid.render({})}else{bricks.show_error(r.options)}})" + }, + { + "wid": "self", + "event": "disable_user", + "actiontype": "script", + "target": "self", + "script": "var tid=bricks.getWidgetById('users_tbl');var d=tid.select_row.user_data;fetch('/rbac/users/disable_user.dspy?id='+d.id,{method:'POST'}).then(function(r){return r.json()}).then(function(r){if(r.widgettype==='Message'){tid.render({})}else{bricks.show_error(r.options)}})" + }, + { + "wid": "self", + "event": "reset_password", + "actiontype": "urlwidget", + "target": "PopupWindow", + "popup_options": { + "title": "重置密码", + "resizable": true, + "height": "60%", + "width": "40%" + }, + "options": { + "method": "POST", + "params": {}, + "url": "{{entire_url('/rbac/admin_reset_password.ui')}}" + } + }, + { + "wid": "self", + "event": "clear_login_fail", + "actiontype": "urlwidget", + "target": "self", + "conform": { + "title": "清除登录次数", + "message": "确认清除该用户的连续登录失败次数?" + }, + "options": { + "method": "POST", + "params": {}, + "url": "{{entire_url('/rbac/api/clear_login_fail.dspy')}}" + }, + "params_mapping": { + "mapping": { + "id": "id" + }, + "need_others": false + } + } + ], "subtables": [ { "field":"userid", diff --git a/scripts/load_path.py b/scripts/load_path.py index bfaeab4..f689e8a 100644 --- a/scripts/load_path.py +++ b/scripts/load_path.py @@ -83,6 +83,7 @@ PATHS_LOGINED = [ # 管理员对他人的敏感操作端点,绝不进 PATHS_LOGINED(否则任何登录用户可重置他人密码)。 # 与存量 /rbac/users/*.dspy(enable/disable/update)的 *.admin 授权口径一致。 PATHS_ADMIN = [ + f"/{MOD}/admin_reset_password.ui", f"/{MOD}/api/admin_reset_password.dspy", f"/{MOD}/api/clear_login_fail.dspy", ] diff --git a/wwwroot/admin_reset_password.ui b/wwwroot/admin_reset_password.ui new file mode 100644 index 0000000..404af7f --- /dev/null +++ b/wwwroot/admin_reset_password.ui @@ -0,0 +1,43 @@ +{ + "widgettype": "Form", + "options": { + "title": "重置密码", + "description": "为选中用户设置新密码(至少8位)", + "fields": [ + { + "name": "userid", + "uitype": "hide", + "value": "{{params_kw.get('id','')}}" + }, + { + "name": "new_password", + "type": "str", + "length": 255, + "uitype": "password", + "datatype": "str", + "required": true, + "label": "新密码" + }, + { + "name": "cfm_password", + "type": "str", + "length": 255, + "uitype": "password", + "datatype": "str", + "required": true, + "label": "确认密码" + } + ] + }, + "binds": [ + { + "wid": "self", + "event": "submit", + "actiontype": "urlwidget", + "target": "self", + "options": { + "url": "{{entire_url('api/admin_reset_password.dspy')}}" + } + } + ] +}