Add more commands to RAGFlow CLI (#12731)

### What problem does this PR solve?

This PR is going to make RAGFlow CLI to access RAGFlow as normal user,
and work as the a testing tool for RAGFlow server.

### Type of change

- [x] New Feature (non-breaking change which adds functionality)

---------

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
This commit is contained in:
Jin Hai
2026-01-21 18:49:52 +08:00
committed by GitHub
parent 6cd4fd91e6
commit 2e2c8f6ca9
8 changed files with 2387 additions and 1173 deletions

View File

@ -484,7 +484,7 @@ def get_environments():
return error_response(str(e), 500)
@admin_bp.route("/users/<username>/new_token", methods=["POST"])
@admin_bp.route("/users/<username>/keys", methods=["POST"])
@login_required
@check_admin_auth
def generate_user_api_key(username: str) -> tuple[Response, int]:
@ -496,10 +496,10 @@ def generate_user_api_key(username: str) -> tuple[Response, int]:
if not tenants:
return error_response("Tenant not found!", 404)
tenant_id: str = tenants[0]["tenant_id"]
token: str = generate_confirmation_token()
key: str = generate_confirmation_token()
obj: dict[str, Any] = {
"tenant_id": tenant_id,
"token": token,
"token": key,
"beta": generate_confirmation_token().replace("ragflow-", "")[:32],
"create_time": current_timestamp(),
"create_date": datetime_format(datetime.now()),
@ -507,7 +507,7 @@ def generate_user_api_key(username: str) -> tuple[Response, int]:
"update_date": None,
}
if not UserMgr.save_api_token(obj):
if not UserMgr.save_api_key(obj):
return error_response("Failed to generate API key!", 500)
return success_response(obj, "API key generated successfully")
except AdminException as e:
@ -516,7 +516,7 @@ def generate_user_api_key(username: str) -> tuple[Response, int]:
return error_response(str(e), 500)
@admin_bp.route("/users/<username>/token_list", methods=["GET"])
@admin_bp.route("/users/<username>/keys", methods=["GET"])
@login_required
@check_admin_auth
def get_user_api_keys(username: str) -> tuple[Response, int]:
@ -529,12 +529,12 @@ def get_user_api_keys(username: str) -> tuple[Response, int]:
return error_response(str(e), 500)
@admin_bp.route("/users/<username>/token/<token>", methods=["DELETE"])
@admin_bp.route("/users/<username>/keys/<key>", methods=["DELETE"])
@login_required
@check_admin_auth
def delete_user_api_key(username: str, token: str) -> tuple[Response, int]:
def delete_user_api_key(username: str, key: str) -> tuple[Response, int]:
try:
deleted = UserMgr.delete_api_token(username, token)
deleted = UserMgr.delete_api_key(username, key)
if deleted:
return success_response(None, "API key deleted successfully")
else:

View File

@ -159,21 +159,21 @@ class UserMgr:
# tenant_id is typically the same as user_id for the owner tenant
tenant_id: str = usr.id
# Query all API tokens for this tenant
api_tokens: Any = APITokenService.query(tenant_id=tenant_id)
# Query all API keys for this tenant
api_keys: Any = APITokenService.query(tenant_id=tenant_id)
result: list[dict[str, Any]] = []
for token_obj in api_tokens:
result.append(token_obj.to_dict())
for key in api_keys:
result.append(key.to_dict())
return result
@staticmethod
def save_api_token(api_token: dict[str, Any]) -> bool:
return APITokenService.save(**api_token)
def save_api_key(api_key: dict[str, Any]) -> bool:
return APITokenService.save(**api_key)
@staticmethod
def delete_api_token(username: str, token: str) -> bool:
def delete_api_key(username: str, key: str) -> bool:
# use email to find user. check exist and unique.
user_list: list[Any] = UserService.query_user_by_email(username)
if not user_list:
@ -185,8 +185,8 @@ class UserMgr:
# tenant_id is typically the same as user_id for the owner tenant
tenant_id: str = usr.id
# Delete the API token
deleted_count: int = APITokenService.filter_delete([APIToken.tenant_id == tenant_id, APIToken.token == token])
# Delete the API key
deleted_count: int = APITokenService.filter_delete([APIToken.tenant_id == tenant_id, APIToken.token == key])
return deleted_count > 0
@staticmethod
@ -305,6 +305,13 @@ class ServiceMgr:
raise AdminException(f"invalid service_index: {service_idx}")
service_config = configs[service_idx]
# exclude retrieval service if retrieval_type is not matched
doc_engine = os.getenv("DOC_ENGINE", "elasticsearch")
if service_config.service_type == "retrieval":
if service_config.retrieval_type != doc_engine:
raise AdminException(f"invalid service_index: {service_idx}")
service_info = {"name": service_config.name, "detail_func_name": service_config.detail_func_name}
detail_func = getattr(health_utils, service_info.get("detail_func_name"))