xiaolongmr commited on
Commit ·
2f8bea9
1
Parent(s): 04e2018
修复模型切换额度不限时的问题
Browse files- api/accounts.py +18 -2
- services/auth_service.py +24 -0
- test/test_account_image_capabilities.py +13 -0
api/accounts.py
CHANGED
|
@@ -255,7 +255,15 @@ def create_router() -> APIRouter:
|
|
| 255 |
@router.delete("/api/auth/users/{key_id}")
|
| 256 |
async def delete_user_key(key_id: str, authorization: str | None = Header(default=None)):
|
| 257 |
require_admin(authorization)
|
| 258 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 259 |
raise HTTPException(status_code=404, detail={"error": "这条用户密钥不存在,可能已经被删除"})
|
| 260 |
return {"items": auth_service.list_keys(role="user")}
|
| 261 |
|
|
@@ -293,7 +301,15 @@ def create_router() -> APIRouter:
|
|
| 293 |
@router.delete("/api/auth/normal-users/{key_id}")
|
| 294 |
async def delete_normal_user_key(key_id: str, authorization: str | None = Header(default=None)):
|
| 295 |
require_admin(authorization)
|
| 296 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 297 |
raise HTTPException(status_code=404, detail={"error": "这条普通用户密钥不存在,可能已经被删除"})
|
| 298 |
return {"items": auth_service.list_keys(role="normal")}
|
| 299 |
|
|
|
|
| 255 |
@router.delete("/api/auth/users/{key_id}")
|
| 256 |
async def delete_user_key(key_id: str, authorization: str | None = Header(default=None)):
|
| 257 |
require_admin(authorization)
|
| 258 |
+
try:
|
| 259 |
+
deleted = auth_service.delete_key(key_id, role="user")
|
| 260 |
+
except Exception as exc:
|
| 261 |
+
print(f"[auth-api] delete internal user {key_id} failed: {exc}")
|
| 262 |
+
raise HTTPException(
|
| 263 |
+
status_code=503,
|
| 264 |
+
detail={"error": "删除内部用户失败,请检查存储后端日志"},
|
| 265 |
+
) from exc
|
| 266 |
+
if not deleted:
|
| 267 |
raise HTTPException(status_code=404, detail={"error": "这条用户密钥不存在,可能已经被删除"})
|
| 268 |
return {"items": auth_service.list_keys(role="user")}
|
| 269 |
|
|
|
|
| 301 |
@router.delete("/api/auth/normal-users/{key_id}")
|
| 302 |
async def delete_normal_user_key(key_id: str, authorization: str | None = Header(default=None)):
|
| 303 |
require_admin(authorization)
|
| 304 |
+
try:
|
| 305 |
+
deleted = auth_service.delete_key(key_id, role="normal")
|
| 306 |
+
except Exception as exc:
|
| 307 |
+
print(f"[auth-api] delete normal user {key_id} failed: {exc}")
|
| 308 |
+
raise HTTPException(
|
| 309 |
+
status_code=503,
|
| 310 |
+
detail={"error": "删除普通用户失败,请检查存储后端日志"},
|
| 311 |
+
) from exc
|
| 312 |
+
if not deleted:
|
| 313 |
raise HTTPException(status_code=404, detail={"error": "这条普通用户密钥不存在,可能已经被删除"})
|
| 314 |
return {"items": auth_service.list_keys(role="normal")}
|
| 315 |
|
services/auth_service.py
CHANGED
|
@@ -1139,6 +1139,30 @@ class AuthService:
|
|
| 1139 |
normalized_id = self._clean(key_id)
|
| 1140 |
if not normalized_id:
|
| 1141 |
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1142 |
def mutate(items: list[dict[str, object]]) -> tuple[list[dict[str, object]], bool]:
|
| 1143 |
next_items = [
|
| 1144 |
item
|
|
|
|
| 1139 |
normalized_id = self._clean(key_id)
|
| 1140 |
if not normalized_id:
|
| 1141 |
return False
|
| 1142 |
+
|
| 1143 |
+
# Database-backed stores can delete one row directly. Avoid loading,
|
| 1144 |
+
# normalizing, and rewriting every user record: a single malformed
|
| 1145 |
+
# legacy row should not prevent an unrelated user from being deleted.
|
| 1146 |
+
merge_auth_keys = getattr(self.storage, "merge_auth_keys", None)
|
| 1147 |
+
if callable(merge_auth_keys):
|
| 1148 |
+
with self._lock:
|
| 1149 |
+
items = self._load(fallback=self._items)
|
| 1150 |
+
target = next(
|
| 1151 |
+
(
|
| 1152 |
+
item
|
| 1153 |
+
for item in items
|
| 1154 |
+
if item.get("id") == normalized_id
|
| 1155 |
+
and (role is None or item.get("role") == role)
|
| 1156 |
+
),
|
| 1157 |
+
None,
|
| 1158 |
+
)
|
| 1159 |
+
if target is None:
|
| 1160 |
+
self._items = items
|
| 1161 |
+
return False
|
| 1162 |
+
merge_auth_keys([], [normalized_id])
|
| 1163 |
+
self._items = [item for item in items if item.get("id") != normalized_id]
|
| 1164 |
+
return True
|
| 1165 |
+
|
| 1166 |
def mutate(items: list[dict[str, object]]) -> tuple[list[dict[str, object]], bool]:
|
| 1167 |
next_items = [
|
| 1168 |
item
|
test/test_account_image_capabilities.py
CHANGED
|
@@ -684,6 +684,19 @@ class AuthServiceTests(unittest.TestCase):
|
|
| 684 |
self.assertFalse(service.delete_key(item["id"], role="user"))
|
| 685 |
self.assertEqual(service.list_keys(role="user"), [])
|
| 686 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 687 |
def test_account_pool_enabled_defaults_to_off_and_can_be_enabled(self) -> None:
|
| 688 |
with tempfile.TemporaryDirectory() as tmp_dir:
|
| 689 |
service = AuthService(JSONStorageBackend(Path(tmp_dir) / "accounts.json", Path(tmp_dir) / "auth_keys.json"))
|
|
|
|
| 684 |
self.assertFalse(service.delete_key(item["id"], role="user"))
|
| 685 |
self.assertEqual(service.list_keys(role="user"), [])
|
| 686 |
|
| 687 |
+
def test_database_delete_key_removes_only_target_row(self) -> None:
|
| 688 |
+
with tempfile.TemporaryDirectory() as tmp_dir:
|
| 689 |
+
backend = DatabaseStorageBackend(f"sqlite:///{(Path(tmp_dir) / 'shared.db').as_posix()}")
|
| 690 |
+
try:
|
| 691 |
+
service = AuthService(backend)
|
| 692 |
+
first, _ = service.create_key(role="normal", name="First")
|
| 693 |
+
second, _ = service.create_key(role="normal", name="Second")
|
| 694 |
+
|
| 695 |
+
self.assertTrue(service.delete_key(first["id"], role="normal"))
|
| 696 |
+
self.assertEqual([item["id"] for item in service.list_keys(role="normal")], [second["id"]])
|
| 697 |
+
finally:
|
| 698 |
+
backend.engine.dispose()
|
| 699 |
+
|
| 700 |
def test_account_pool_enabled_defaults_to_off_and_can_be_enabled(self) -> None:
|
| 701 |
with tempfile.TemporaryDirectory() as tmp_dir:
|
| 702 |
service = AuthService(JSONStorageBackend(Path(tmp_dir) / "accounts.json", Path(tmp_dir) / "auth_keys.json"))
|