This commit is contained in:
277
elastic/views.py
277
elastic/views.py
@@ -489,6 +489,8 @@ def update_user_by_id_view(request, user_id):
|
||||
new_username = (payload.get("username") or "").strip()
|
||||
new_permission = payload.get("permission")
|
||||
new_password = (payload.get("password") or "").strip()
|
||||
raw_keys = payload.get("key", None)
|
||||
raw_manage_keys = payload.get("manage_key", None)
|
||||
if new_password and len(new_password) < 6:
|
||||
return JsonResponse({"status": "error", "message": "密码长度至少为6位"}, status=400)
|
||||
|
||||
@@ -498,6 +500,28 @@ def update_user_by_id_view(request, user_id):
|
||||
requester_mgr = set(requester.get("manage_key") or [])
|
||||
target_keys = set(target.get("key") or [])
|
||||
|
||||
def normalize_keys(v):
|
||||
if v is None:
|
||||
return None
|
||||
if isinstance(v, list):
|
||||
parts = v
|
||||
elif isinstance(v, str):
|
||||
parts = re.split(r"[,,;;、\r\n]+", v)
|
||||
else:
|
||||
parts = [v]
|
||||
out = []
|
||||
seen = set()
|
||||
for p in parts:
|
||||
s = str(p).strip().strip(";")
|
||||
if not s or s in seen:
|
||||
continue
|
||||
seen.add(s)
|
||||
out.append(s)
|
||||
return out
|
||||
|
||||
new_keys = normalize_keys(raw_keys)
|
||||
new_manage_keys = normalize_keys(raw_manage_keys)
|
||||
|
||||
if is_admin:
|
||||
if new_username:
|
||||
other = get_user_by_username(new_username)
|
||||
@@ -508,6 +532,8 @@ def update_user_by_id_view(request, user_id):
|
||||
username=new_username if new_username else None,
|
||||
permission=int(new_permission) if new_permission is not None else None,
|
||||
password=new_password if new_password else None,
|
||||
key=new_keys,
|
||||
manage_key=new_manage_keys,
|
||||
)
|
||||
return JsonResponse({"status": "success"}) if ok else JsonResponse({"status": "error", "message": "用户更新失败"}, status=500)
|
||||
|
||||
@@ -518,9 +544,25 @@ def update_user_by_id_view(request, user_id):
|
||||
return JsonResponse({"status": "success"}) if ok else JsonResponse({"status": "error", "message": "用户更新失败"}, status=500)
|
||||
|
||||
if requester_mgr and (target_keys & requester_mgr):
|
||||
if not new_password or new_username or new_permission is not None:
|
||||
return JsonResponse({"status": "error", "message": "导师仅允许修改密码"}, status=403)
|
||||
ok = es_update_user_by_id(user_id, password=new_password)
|
||||
if new_username or new_permission is not None or new_manage_keys is not None:
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
if not new_password and new_keys is None:
|
||||
return JsonResponse({"status": "error", "message": "缺少更新内容"}, status=400)
|
||||
merged_keys = None
|
||||
if new_keys is not None:
|
||||
try:
|
||||
new_keys_set = set(new_keys)
|
||||
except Exception:
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
requester_locked = set(normalize_keys(requester.get("key")) or [])
|
||||
if new_keys_set & requester_locked:
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
existing_keys = [str(v).strip() for v in list(target.get("key") or []) if str(v).strip()]
|
||||
preserved = [k for k in existing_keys if k in requester_locked]
|
||||
merged_keys = preserved + [str(v).strip() for v in list(new_keys) if str(v).strip() and str(v).strip() not in requester_locked]
|
||||
seen = set()
|
||||
merged_keys = [k for k in merged_keys if not (k in seen or seen.add(k))]
|
||||
ok = es_update_user_by_id(user_id, password=new_password if new_password else None, key=merged_keys)
|
||||
return JsonResponse({"status": "success"}) if ok else JsonResponse({"status": "error", "message": "用户更新失败"}, status=500)
|
||||
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
@@ -1019,17 +1061,39 @@ def analytics_recent_view(request):
|
||||
@require_http_methods(["POST"])
|
||||
@csrf_protect
|
||||
def remove_key_view(request):
|
||||
if request.session.get("user_id") is None:
|
||||
return JsonResponse({"status": "error", "message": "未登录"}, status=401)
|
||||
is_admin = int(request.session.get("permission", 1)) == 0
|
||||
try:
|
||||
payload = json.loads(request.body.decode("utf-8"))
|
||||
key_to_remove = payload.get("key")
|
||||
|
||||
if not key_to_remove:
|
||||
return JsonResponse({"status": "error", "message": "缺少key参数"}, status=400)
|
||||
key_to_remove = str(key_to_remove).strip()
|
||||
if not key_to_remove:
|
||||
return JsonResponse({"status": "error", "message": "缺少key参数"}, status=400)
|
||||
|
||||
if not is_admin:
|
||||
me = get_user_by_id(request.session.get("user_id")) or {}
|
||||
if not (me.get("manage_key") or []):
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
allowed = {str(x).strip() for x in list(request.session.get("tutor_added_manage_keys") or []) if str(x).strip()}
|
||||
if key_to_remove not in allowed:
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
|
||||
from .es_connect import delete_key_globally
|
||||
ok, count = delete_key_globally(key_to_remove)
|
||||
|
||||
if ok:
|
||||
if not is_admin:
|
||||
cur = [str(x).strip() for x in list(request.session.get("tutor_added_manage_keys") or []) if str(x).strip()]
|
||||
cur = [k for k in cur if k != key_to_remove]
|
||||
request.session["tutor_added_manage_keys"] = cur
|
||||
try:
|
||||
request.session.modified = True
|
||||
except Exception:
|
||||
pass
|
||||
return JsonResponse({"status": "success", "message": f"已成功全局删除 Key '{key_to_remove}',并同步清理了 {count} 个注册码。"})
|
||||
else:
|
||||
return JsonResponse({"status": "error", "message": "删除失败"}, status=500)
|
||||
@@ -1039,6 +1103,35 @@ def remove_key_view(request):
|
||||
except Exception as e:
|
||||
return JsonResponse({"status": "error", "message": str(e)}, status=500)
|
||||
|
||||
@require_http_methods(["POST"])
|
||||
@csrf_protect
|
||||
def unallow_tutor_added_key_view(request):
|
||||
if request.session.get("user_id") is None:
|
||||
return JsonResponse({"status": "error", "message": "未登录"}, status=401)
|
||||
if int(request.session.get("permission", 1)) == 0:
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
me = get_user_by_id(request.session.get("user_id")) or {}
|
||||
if not (me.get("manage_key") or []):
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
try:
|
||||
payload = json.loads(request.body.decode("utf-8"))
|
||||
except Exception:
|
||||
return JsonResponse({"status": "error", "message": "JSON无效"}, status=400)
|
||||
key_name = (payload.get("key") or "").strip()
|
||||
if not key_name:
|
||||
return JsonResponse({"status": "error", "message": "key不能为空"}, status=400)
|
||||
cur = list(request.session.get("tutor_added_manage_keys") or [])
|
||||
cur = [str(x).strip() for x in cur if str(x).strip()]
|
||||
if key_name not in cur:
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
cur = [k for k in cur if k != key_name]
|
||||
request.session["tutor_added_manage_keys"] = cur
|
||||
try:
|
||||
request.session.modified = True
|
||||
except Exception:
|
||||
pass
|
||||
return JsonResponse({"status": "success"})
|
||||
|
||||
@require_http_methods(["GET"])
|
||||
@ensure_csrf_cookie
|
||||
def user_manage(request):
|
||||
@@ -1049,6 +1142,15 @@ def user_manage(request):
|
||||
is_admin = int(request.session.get("permission", 1)) == 0
|
||||
me = get_user_by_id(session_user_id) or {}
|
||||
has_manage = bool(me.get("manage_key"))
|
||||
manage_keys = list(me.get("manage_key") or [])
|
||||
raw_my_keys = me.get("key") or []
|
||||
if isinstance(raw_my_keys, list):
|
||||
my_keys = raw_my_keys
|
||||
elif isinstance(raw_my_keys, str):
|
||||
my_keys = re.split(r"[,,;;、\r\n]+", raw_my_keys)
|
||||
else:
|
||||
my_keys = [raw_my_keys]
|
||||
my_keys = [str(x).strip() for x in my_keys if str(x).strip()]
|
||||
user_id_qs = request.GET.get("user_id")
|
||||
context = {
|
||||
"user_id": user_id_qs or session_user_id,
|
||||
@@ -1056,6 +1158,8 @@ def user_manage(request):
|
||||
"is_admin": is_admin,
|
||||
"is_tutor": (not is_admin) and has_manage,
|
||||
"is_student": (not is_admin) and (not has_manage),
|
||||
"manage_keys_json": json.dumps(manage_keys, ensure_ascii=False),
|
||||
"my_keys_json": json.dumps(my_keys, ensure_ascii=False),
|
||||
}
|
||||
return render(request, "elastic/users.html", context)
|
||||
|
||||
@@ -1066,14 +1170,36 @@ def registration_code_manage_page(request):
|
||||
if session_user_id is None:
|
||||
from django.shortcuts import redirect
|
||||
return redirect("/accounts/login/")
|
||||
if int(request.session.get("permission", 1)) != 0:
|
||||
is_admin = int(request.session.get("permission", 1)) == 0
|
||||
me = get_user_by_id(session_user_id) or {}
|
||||
has_manage = bool(me.get("manage_key"))
|
||||
can_manage_reg = int(me.get("can_manage_registration_codes") or 0) == 1
|
||||
if (not is_admin) and (not has_manage) and (not can_manage_reg):
|
||||
from django.shortcuts import redirect
|
||||
return redirect("/main/home/")
|
||||
user_id_qs = request.GET.get("user_id")
|
||||
me = get_user_by_id(session_user_id) or {}
|
||||
raw_my_keys = me.get("key") or []
|
||||
if isinstance(raw_my_keys, list):
|
||||
my_keys = raw_my_keys
|
||||
elif isinstance(raw_my_keys, str):
|
||||
my_keys = re.split(r"[,,;;、\r\n]+", raw_my_keys)
|
||||
else:
|
||||
my_keys = [raw_my_keys]
|
||||
my_keys = [str(x).strip() for x in my_keys if str(x).strip()]
|
||||
if can_manage_reg and (not has_manage) and (not is_admin):
|
||||
allowed_manage_keys = [str(x).strip() for x in list(me.get("registration_manage_keys") or []) if str(x).strip()]
|
||||
else:
|
||||
allowed_manage_keys = list(request.session.get("tutor_added_manage_keys") or [])
|
||||
allowed_manage_keys = [str(x).strip() for x in allowed_manage_keys if str(x).strip()]
|
||||
context = {
|
||||
"user_id": user_id_qs or session_user_id,
|
||||
"username": me.get("username"),
|
||||
"is_admin": is_admin,
|
||||
"has_manage_key": has_manage,
|
||||
"can_manage_registration_codes": can_manage_reg,
|
||||
"my_keys_json": json.dumps(my_keys, ensure_ascii=False),
|
||||
"manage_keys_json": json.dumps(list(me.get("manage_key") or []), ensure_ascii=False),
|
||||
"allowed_manage_keys_json": json.dumps(allowed_manage_keys, ensure_ascii=False),
|
||||
}
|
||||
return render(request, "elastic/registration_codes.html", context)
|
||||
|
||||
@@ -1081,8 +1207,16 @@ def registration_code_manage_page(request):
|
||||
def get_keys_list_view(request):
|
||||
if request.session.get("user_id") is None:
|
||||
return JsonResponse({"status": "error", "message": "未登录"}, status=401)
|
||||
if int(request.session.get("permission", 1)) != 0:
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
is_admin = int(request.session.get("permission", 1)) == 0
|
||||
if not is_admin:
|
||||
me = get_user_by_id(request.session.get("user_id")) or {}
|
||||
has_manage = bool(me.get("manage_key") or [])
|
||||
can_manage_reg = int(me.get("can_manage_registration_codes") or 0) == 1
|
||||
if (not has_manage) and (not can_manage_reg):
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
if can_manage_reg and (not has_manage):
|
||||
lst = [str(x).strip() for x in list(me.get("registration_manage_keys") or []) if str(x).strip()]
|
||||
return JsonResponse({"status": "success", "data": lst})
|
||||
lst = get_keys_list()
|
||||
return JsonResponse({"status": "success", "data": lst})
|
||||
|
||||
@@ -1091,8 +1225,13 @@ def get_keys_list_view(request):
|
||||
def add_key_view(request):
|
||||
if request.session.get("user_id") is None:
|
||||
return JsonResponse({"status": "error", "message": "未登录"}, status=401)
|
||||
if int(request.session.get("permission", 1)) != 0:
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
is_admin = int(request.session.get("permission", 1)) == 0
|
||||
if not is_admin:
|
||||
me = get_user_by_id(request.session.get("user_id")) or {}
|
||||
has_manage = bool(me.get("manage_key") or [])
|
||||
can_manage_reg = int(me.get("can_manage_registration_codes") or 0) == 1
|
||||
if (not has_manage) and (not can_manage_reg):
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
try:
|
||||
payload = json.loads(request.body.decode("utf-8"))
|
||||
except Exception:
|
||||
@@ -1100,9 +1239,29 @@ def add_key_view(request):
|
||||
key_name = (payload.get("key") or "").strip()
|
||||
if not key_name:
|
||||
return JsonResponse({"status": "error", "message": "key不能为空"}, status=400)
|
||||
cur_global = set(get_keys_list() or [])
|
||||
if key_name in cur_global:
|
||||
return JsonResponse({"status": "error", "message": "key已存在"}, status=409)
|
||||
ok = ensure_key_in_list(key_name)
|
||||
if not ok:
|
||||
return JsonResponse({"status": "error", "message": "key已存在或写入失败"}, status=409)
|
||||
return JsonResponse({"status": "error", "message": "写入失败"}, status=500)
|
||||
if not is_admin:
|
||||
uid = request.session.get("user_id")
|
||||
if has_manage:
|
||||
cur = list(request.session.get("tutor_added_manage_keys") or [])
|
||||
cur = [str(x).strip() for x in cur if str(x).strip()]
|
||||
if key_name not in cur:
|
||||
cur.append(key_name)
|
||||
request.session["tutor_added_manage_keys"] = cur
|
||||
try:
|
||||
request.session.modified = True
|
||||
except Exception:
|
||||
pass
|
||||
elif can_manage_reg:
|
||||
cur = [str(x).strip() for x in list((me or {}).get("registration_manage_keys") or []) if str(x).strip()]
|
||||
if key_name not in cur:
|
||||
cur.append(key_name)
|
||||
es_update_user_by_id(uid, registration_manage_keys=cur)
|
||||
return JsonResponse({"status": "success"})
|
||||
|
||||
@require_http_methods(["POST"])
|
||||
@@ -1110,19 +1269,89 @@ def add_key_view(request):
|
||||
def generate_registration_code_view(request):
|
||||
if request.session.get("user_id") is None:
|
||||
return JsonResponse({"status": "error", "message": "未登录"}, status=401)
|
||||
if int(request.session.get("permission", 1)) != 0:
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
uid = request.session.get("user_id")
|
||||
is_admin = int(request.session.get("permission", 1)) == 0
|
||||
if not is_admin:
|
||||
me = get_user_by_id(uid) or {}
|
||||
has_manage = bool(me.get("manage_key") or [])
|
||||
can_manage_reg = int(me.get("can_manage_registration_codes") or 0) == 1
|
||||
if (not has_manage) and (not can_manage_reg):
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
try:
|
||||
payload = json.loads(request.body.decode("utf-8"))
|
||||
except Exception:
|
||||
return JsonResponse({"status": "error", "message": "JSON无效"}, status=400)
|
||||
keys = list(payload.get("keys") or [])
|
||||
manage_keys = list(payload.get("manage_keys") or [])
|
||||
if not is_admin:
|
||||
if has_manage:
|
||||
my_keys = []
|
||||
try:
|
||||
my_keys = [str(x).strip() for x in list((me or {}).get("key") or []) if str(x).strip()]
|
||||
except Exception:
|
||||
my_keys = []
|
||||
allowed_manage = set()
|
||||
try:
|
||||
allowed_manage = {str(x).strip() for x in list(request.session.get("tutor_added_manage_keys") or []) if str(x).strip()}
|
||||
except Exception:
|
||||
allowed_manage = set()
|
||||
normalized_keys = []
|
||||
seen = set()
|
||||
for v in list(keys or []):
|
||||
s = str(v).strip()
|
||||
if not s or s in seen:
|
||||
continue
|
||||
seen.add(s)
|
||||
normalized_keys.append(s)
|
||||
missing = [k for k in my_keys if k not in seen]
|
||||
if missing:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": f"必须选择导师原有的 key:{'、'.join(missing)}"},
|
||||
status=400,
|
||||
)
|
||||
keys = normalized_keys
|
||||
clean_manage = []
|
||||
manage_seen = set()
|
||||
for v in list(manage_keys or []):
|
||||
s = str(v).strip()
|
||||
if not s or s in manage_seen:
|
||||
continue
|
||||
if s not in allowed_manage:
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
manage_seen.add(s)
|
||||
clean_manage.append(s)
|
||||
manage_keys = clean_manage
|
||||
else:
|
||||
allowed = {str(x).strip() for x in list((me or {}).get("registration_manage_keys") or []) if str(x).strip()}
|
||||
norm_keys = []
|
||||
seen = set()
|
||||
for v in list(keys or []):
|
||||
s = str(v).strip()
|
||||
if not s or s in seen:
|
||||
continue
|
||||
if s not in allowed:
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
seen.add(s)
|
||||
norm_keys.append(s)
|
||||
if not norm_keys:
|
||||
return JsonResponse({"status": "error", "message": "至少选择一个 key"}, status=400)
|
||||
keys = norm_keys
|
||||
clean_manage = []
|
||||
manage_seen = set()
|
||||
for v in list(manage_keys or []):
|
||||
s = str(v).strip()
|
||||
if not s or s in manage_seen:
|
||||
continue
|
||||
if s not in allowed:
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
manage_seen.add(s)
|
||||
clean_manage.append(s)
|
||||
manage_keys = clean_manage
|
||||
try:
|
||||
days = int(payload.get("expires_in_days", 30))
|
||||
except Exception:
|
||||
days = 30
|
||||
result = generate_registration_code(keys=keys, manage_keys=manage_keys, expires_in_days=days, created_by=request.session.get("user_id"))
|
||||
result = generate_registration_code(keys=keys, manage_keys=manage_keys, expires_in_days=days, created_by=uid)
|
||||
if not result:
|
||||
return JsonResponse({"status": "error", "message": "生成失败"}, status=500)
|
||||
return JsonResponse({"status": "success", "data": result})
|
||||
@@ -1131,9 +1360,15 @@ def generate_registration_code_view(request):
|
||||
def list_registration_codes_view(request):
|
||||
if request.session.get("user_id") is None:
|
||||
return JsonResponse({"status": "error", "message": "未登录"}, status=401)
|
||||
if int(request.session.get("permission", 1)) != 0:
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
uid = request.session.get("user_id")
|
||||
is_admin = int(request.session.get("permission", 1)) == 0
|
||||
if not is_admin:
|
||||
me = get_user_by_id(uid) or {}
|
||||
if (not (me.get("manage_key") or [])) and (int(me.get("can_manage_registration_codes") or 0) != 1):
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
data = list_registration_codes()
|
||||
if not is_admin:
|
||||
data = [it for it in (data or []) if str(it.get("created_by")) == str(uid)]
|
||||
return JsonResponse({"status": "success", "data": data})
|
||||
|
||||
|
||||
@@ -1198,8 +1433,12 @@ def keys_for_filter_view(request):
|
||||
def revoke_registration_code_view(request):
|
||||
if request.session.get("user_id") is None:
|
||||
return JsonResponse({"status": "error", "message": "未登录"}, status=401)
|
||||
if int(request.session.get("permission", 1)) != 0:
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
uid = request.session.get("user_id")
|
||||
is_admin = int(request.session.get("permission", 1)) == 0
|
||||
if not is_admin:
|
||||
me = get_user_by_id(uid) or {}
|
||||
if (not (me.get("manage_key") or [])) and (int(me.get("can_manage_registration_codes") or 0) != 1):
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
try:
|
||||
payload = json.loads(request.body.decode("utf-8"))
|
||||
except Exception:
|
||||
@@ -1207,6 +1446,10 @@ def revoke_registration_code_view(request):
|
||||
code = (payload.get("code") or "").strip()
|
||||
if not code:
|
||||
return JsonResponse({"status": "error", "message": "缺少code"}, status=400)
|
||||
if not is_admin:
|
||||
info = get_registration_code(code)
|
||||
if not info or str(info.get("created_by")) != str(uid):
|
||||
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
|
||||
ok = revoke_registration_code(code)
|
||||
if not ok:
|
||||
return JsonResponse({"status": "error", "message": "作废失败"}, status=500)
|
||||
|
||||
Reference in New Issue
Block a user