mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-03-26 08:49:56 +08:00
Refa: Searches /search API to RESTFul (#13770)
### What problem does this PR solve? Searches /search API to RESTFul ### Type of change - [x] Documentation Update - [x] Refactoring Co-authored-by: Jin Hai <haijin.chn@gmail.com> Co-authored-by: Yingfeng <yingfeng.zhang@gmail.com>
This commit is contained in:
@ -24,10 +24,10 @@ from api.db.services.search_service import SearchService
|
||||
from api.db.services.user_service import TenantService, UserTenantService
|
||||
from common.misc_utils import get_uuid
|
||||
from common.constants import RetCode, StatusEnum
|
||||
from api.utils.api_utils import get_data_error_result, get_json_result, not_allowed_parameters, get_request_json, server_error_response, validate_request
|
||||
from api.utils.api_utils import get_data_error_result, get_json_result, get_request_json, server_error_response, validate_request
|
||||
|
||||
|
||||
@manager.route("/create", methods=["post"]) # noqa: F821
|
||||
@manager.route("/searches", methods=["POST"]) # noqa: F821
|
||||
@login_required
|
||||
@validate_request("name")
|
||||
async def create():
|
||||
@ -61,67 +61,34 @@ async def create():
|
||||
return server_error_response(e)
|
||||
|
||||
|
||||
@manager.route("/update", methods=["post"]) # noqa: F821
|
||||
@manager.route("/searches", methods=["GET"]) # noqa: F821
|
||||
@login_required
|
||||
@validate_request("search_id", "name", "search_config", "tenant_id")
|
||||
@not_allowed_parameters("id", "created_by", "create_time", "update_time", "create_date", "update_date", "created_by")
|
||||
async def update():
|
||||
req = await get_request_json()
|
||||
if not isinstance(req["name"], str):
|
||||
return get_data_error_result(message="Search name must be string.")
|
||||
if req["name"].strip() == "":
|
||||
return get_data_error_result(message="Search name can't be empty.")
|
||||
if len(req["name"].encode("utf-8")) > DATASET_NAME_LIMIT:
|
||||
return get_data_error_result(message=f"Search name length is {len(req['name'])} which is large than {DATASET_NAME_LIMIT}")
|
||||
req["name"] = req["name"].strip()
|
||||
tenant_id = req["tenant_id"]
|
||||
e, _ = TenantService.get_by_id(tenant_id)
|
||||
if not e:
|
||||
return get_data_error_result(message="Authorized identity.")
|
||||
|
||||
search_id = req["search_id"]
|
||||
if not SearchService.accessible4deletion(search_id, current_user.id):
|
||||
return get_json_result(data=False, message="No authorization.", code=RetCode.AUTHENTICATION_ERROR)
|
||||
def list_searches():
|
||||
keywords = request.args.get("keywords", "")
|
||||
page_number = int(request.args.get("page", 0))
|
||||
items_per_page = int(request.args.get("page_size", 0))
|
||||
orderby = request.args.get("orderby", "create_time")
|
||||
desc = request.args.get("desc", "true").lower() != "false"
|
||||
owner_ids = request.args.getlist("owner_ids")
|
||||
|
||||
try:
|
||||
search_app = SearchService.query(tenant_id=tenant_id, id=search_id)[0]
|
||||
if not search_app:
|
||||
return get_json_result(data=False, message=f"Cannot find search {search_id}", code=RetCode.DATA_ERROR)
|
||||
|
||||
if req["name"].lower() != search_app.name.lower() and len(SearchService.query(name=req["name"], tenant_id=tenant_id, status=StatusEnum.VALID.value)) >= 1:
|
||||
return get_data_error_result(message="Duplicated search name.")
|
||||
|
||||
if "search_config" in req:
|
||||
current_config = search_app.search_config or {}
|
||||
new_config = req["search_config"]
|
||||
|
||||
if not isinstance(new_config, dict):
|
||||
return get_data_error_result(message="search_config must be a JSON object")
|
||||
|
||||
updated_config = {**current_config, **new_config}
|
||||
req["search_config"] = updated_config
|
||||
|
||||
req.pop("search_id", None)
|
||||
req.pop("tenant_id", None)
|
||||
|
||||
updated = SearchService.update_by_id(search_id, req)
|
||||
if not updated:
|
||||
return get_data_error_result(message="Failed to update search")
|
||||
|
||||
e, updated_search = SearchService.get_by_id(search_id)
|
||||
if not e:
|
||||
return get_data_error_result(message="Failed to fetch updated search")
|
||||
|
||||
return get_json_result(data=updated_search.to_dict())
|
||||
|
||||
if not owner_ids:
|
||||
tenants = []
|
||||
search_apps, total = SearchService.get_by_tenant_ids(tenants, current_user.id, page_number, items_per_page, orderby, desc, keywords)
|
||||
else:
|
||||
search_apps, total = SearchService.get_by_tenant_ids(owner_ids, current_user.id, 0, 0, orderby, desc, keywords)
|
||||
search_apps = [s for s in search_apps if s["tenant_id"] in owner_ids]
|
||||
total = len(search_apps)
|
||||
if page_number and items_per_page:
|
||||
search_apps = search_apps[(page_number - 1) * items_per_page: page_number * items_per_page]
|
||||
return get_json_result(data={"search_apps": search_apps, "total": total})
|
||||
except Exception as e:
|
||||
return server_error_response(e)
|
||||
|
||||
|
||||
@manager.route("/detail", methods=["GET"]) # noqa: F821
|
||||
@manager.route("/searches/<search_id>", methods=["GET"]) # noqa: F821
|
||||
@login_required
|
||||
def detail():
|
||||
search_id = request.args["search_id"]
|
||||
def detail(search_id):
|
||||
try:
|
||||
tenants = UserTenantService.query(user_id=current_user.id)
|
||||
for tenant in tenants:
|
||||
@ -138,44 +105,60 @@ def detail():
|
||||
return server_error_response(e)
|
||||
|
||||
|
||||
@manager.route("/list", methods=["POST"]) # noqa: F821
|
||||
@manager.route("/searches/<search_id>", methods=["PUT"]) # noqa: F821
|
||||
@login_required
|
||||
async def list_search_app():
|
||||
keywords = request.args.get("keywords", "")
|
||||
page_number = int(request.args.get("page", 0))
|
||||
items_per_page = int(request.args.get("page_size", 0))
|
||||
orderby = request.args.get("orderby", "create_time")
|
||||
if request.args.get("desc", "true").lower() == "false":
|
||||
desc = False
|
||||
else:
|
||||
desc = True
|
||||
|
||||
@validate_request("name", "search_config")
|
||||
async def update(search_id):
|
||||
req = await get_request_json()
|
||||
owner_ids = req.get("owner_ids", [])
|
||||
if not isinstance(req["name"], str):
|
||||
return get_data_error_result(message="Search name must be string.")
|
||||
if req["name"].strip() == "":
|
||||
return get_data_error_result(message="Search name can't be empty.")
|
||||
if len(req["name"].encode("utf-8")) > DATASET_NAME_LIMIT:
|
||||
return get_data_error_result(message=f"Search name length is {len(req['name'])} which is large than {DATASET_NAME_LIMIT}")
|
||||
req["name"] = req["name"].strip()
|
||||
|
||||
e, _ = TenantService.get_by_id(current_user.id)
|
||||
if not e:
|
||||
return get_data_error_result(message="Authorized identity.")
|
||||
|
||||
if not SearchService.accessible4deletion(search_id, current_user.id):
|
||||
return get_json_result(data=False, message="No authorization.", code=RetCode.AUTHENTICATION_ERROR)
|
||||
|
||||
try:
|
||||
if not owner_ids:
|
||||
# tenants = TenantService.get_joined_tenants_by_user_id(current_user.id)
|
||||
# tenants = [m["tenant_id"] for m in tenants]
|
||||
tenants = []
|
||||
search_apps, total = SearchService.get_by_tenant_ids(tenants, current_user.id, page_number, items_per_page, orderby, desc, keywords)
|
||||
else:
|
||||
tenants = owner_ids
|
||||
search_apps, total = SearchService.get_by_tenant_ids(tenants, current_user.id, 0, 0, orderby, desc, keywords)
|
||||
search_apps = [search_app for search_app in search_apps if search_app["tenant_id"] in tenants]
|
||||
total = len(search_apps)
|
||||
if page_number and items_per_page:
|
||||
search_apps = search_apps[(page_number - 1) * items_per_page : page_number * items_per_page]
|
||||
return get_json_result(data={"search_apps": search_apps, "total": total})
|
||||
search_app = SearchService.query(tenant_id=current_user.id, id=search_id)[0]
|
||||
if not search_app:
|
||||
return get_json_result(data=False, message=f"Cannot find search {search_id}", code=RetCode.DATA_ERROR)
|
||||
|
||||
if req["name"].lower() != search_app.name.lower() and len(SearchService.query(name=req["name"], tenant_id=current_user.id, status=StatusEnum.VALID.value)) >= 1:
|
||||
return get_data_error_result(message="Duplicated search name.")
|
||||
|
||||
current_config = search_app.search_config or {}
|
||||
new_config = req["search_config"]
|
||||
if not isinstance(new_config, dict):
|
||||
return get_data_error_result(message="search_config must be a JSON object")
|
||||
req["search_config"] = {**current_config, **new_config}
|
||||
|
||||
for field in ("search_id", "tenant_id", "created_by", "update_time", "id"):
|
||||
req.pop(field, None)
|
||||
|
||||
updated = SearchService.update_by_id(search_id, req)
|
||||
if not updated:
|
||||
return get_data_error_result(message="Failed to update search")
|
||||
|
||||
e, updated_search = SearchService.get_by_id(search_id)
|
||||
if not e:
|
||||
return get_data_error_result(message="Failed to fetch updated search")
|
||||
|
||||
return get_json_result(data=updated_search.to_dict())
|
||||
|
||||
except Exception as e:
|
||||
return server_error_response(e)
|
||||
|
||||
|
||||
@manager.route("/rm", methods=["post"]) # noqa: F821
|
||||
@manager.route("/searches/<search_id>", methods=["DELETE"]) # noqa: F821
|
||||
@login_required
|
||||
@validate_request("search_id")
|
||||
async def rm():
|
||||
req = await get_request_json()
|
||||
search_id = req["search_id"]
|
||||
def delete_search(search_id):
|
||||
if not SearchService.accessible4deletion(search_id, current_user.id):
|
||||
return get_json_result(data=False, message="No authorization.", code=RetCode.AUTHENTICATION_ERROR)
|
||||
|
||||
@ -7034,3 +7034,305 @@ or
|
||||
"message": "Can't find this dataset!"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SEARCH APP MANAGEMENT
|
||||
|
||||
### Create search app
|
||||
|
||||
**POST** `/api/v1/searches`
|
||||
|
||||
Creates a search app.
|
||||
|
||||
#### Request
|
||||
|
||||
- Method: POST
|
||||
- URL: `/api/v1/searches`
|
||||
- Headers:
|
||||
- `'Content-Type: application/json'`
|
||||
- `'Authorization: Bearer <YOUR_API_KEY>'`
|
||||
- Body:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my_search_app",
|
||||
"description": "optional description"
|
||||
}
|
||||
```
|
||||
|
||||
##### Request example
|
||||
|
||||
```bash
|
||||
curl --request POST \
|
||||
--url 'http://{address}/api/v1/searches' \
|
||||
--header 'Authorization: Bearer <YOUR_API_KEY>' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"name": "my_search_app",
|
||||
"description": "My first search app"
|
||||
}'
|
||||
```
|
||||
|
||||
##### Request parameters
|
||||
|
||||
- `"name"`: (*Body parameter*), `string`, *Required*
|
||||
The name of the search app. Must be unique and no longer than 255 characters.
|
||||
- `"description"`: (*Body parameter*), `string`
|
||||
A brief description of the search app.
|
||||
|
||||
#### Response
|
||||
|
||||
Success:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"search_id": "b330ec2e91ec11efbc510242ac120006"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Failure:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 102,
|
||||
"message": "Search name can't be empty."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### List search apps
|
||||
|
||||
**GET** `/api/v1/searches?keywords={keywords}&page={page}&page_size={page_size}&orderby={orderby}&desc={desc}&owner_ids={owner_ids}`
|
||||
|
||||
Lists search apps for the current user.
|
||||
|
||||
#### Request
|
||||
|
||||
- Method: GET
|
||||
- URL: `/api/v1/searches`
|
||||
- Headers:
|
||||
- `'Authorization: Bearer <YOUR_API_KEY>'`
|
||||
|
||||
##### Request example
|
||||
|
||||
```bash
|
||||
curl --request GET \
|
||||
--url 'http://{address}/api/v1/searches?page=1&page_size=20' \
|
||||
--header 'Authorization: Bearer <YOUR_API_KEY>'
|
||||
```
|
||||
|
||||
##### Request parameters
|
||||
|
||||
- `keywords`: (*Filter parameter*), `string`
|
||||
Search keyword to filter search apps by name.
|
||||
- `page`: (*Filter parameter*), `integer`
|
||||
Specifies the page number. Defaults to `0` (no pagination).
|
||||
- `page_size`: (*Filter parameter*), `integer`
|
||||
The number of items per page. Defaults to `0` (no pagination).
|
||||
- `orderby`: (*Filter parameter*), `string`
|
||||
The field to sort by. Defaults to `create_time`.
|
||||
- `desc`: (*Filter parameter*), `boolean`
|
||||
Whether to sort in descending order. Defaults to `true`.
|
||||
- `owner_ids`: (*Filter parameter*), `string` (repeatable)
|
||||
Filter by owner tenant IDs. Can be specified multiple times: `?owner_ids=id1&owner_ids=id2`.
|
||||
|
||||
#### Response
|
||||
|
||||
Success:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"total": 2,
|
||||
"search_apps": [
|
||||
{
|
||||
"id": "b330ec2e91ec11efbc510242ac120006",
|
||||
"name": "my_search_app",
|
||||
"description": "My first search app",
|
||||
"tenant_id": "7c8983badede11f083f184ba59bc53c7",
|
||||
"create_time": 1729763127646
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Get search app
|
||||
|
||||
**GET** `/api/v1/searches/{search_id}`
|
||||
|
||||
Gets the details of a search app.
|
||||
|
||||
#### Request
|
||||
|
||||
- Method: GET
|
||||
- URL: `/api/v1/searches/{search_id}`
|
||||
- Headers:
|
||||
- `'Authorization: Bearer <YOUR_API_KEY>'`
|
||||
|
||||
##### Request example
|
||||
|
||||
```bash
|
||||
curl --request GET \
|
||||
--url 'http://{address}/api/v1/searches/b330ec2e91ec11efbc510242ac120006' \
|
||||
--header 'Authorization: Bearer <YOUR_API_KEY>'
|
||||
```
|
||||
|
||||
##### Request parameters
|
||||
|
||||
- `search_id`: (*Path parameter*), `string`, *Required*
|
||||
The ID of the search app to retrieve.
|
||||
|
||||
#### Response
|
||||
|
||||
Success:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"id": "b330ec2e91ec11efbc510242ac120006",
|
||||
"name": "my_search_app",
|
||||
"description": "My first search app",
|
||||
"tenant_id": "7c8983badede11f083f184ba59bc53c7",
|
||||
"search_config": {},
|
||||
"create_time": 1729763127646
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Failure:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 102,
|
||||
"message": "Can't find this Search App!"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Update search app
|
||||
|
||||
**PUT** `/api/v1/searches/{search_id}`
|
||||
|
||||
Updates a search app.
|
||||
|
||||
#### Request
|
||||
|
||||
- Method: PUT
|
||||
- URL: `/api/v1/searches/{search_id}`
|
||||
- Headers:
|
||||
- `'Content-Type: application/json'`
|
||||
- `'Authorization: Bearer <YOUR_API_KEY>'`
|
||||
- Body:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "updated_name",
|
||||
"search_config": {"top_k": 5}
|
||||
}
|
||||
```
|
||||
|
||||
##### Request example
|
||||
|
||||
```bash
|
||||
curl --request PUT \
|
||||
--url 'http://{address}/api/v1/searches/b330ec2e91ec11efbc510242ac120006' \
|
||||
--header 'Authorization: Bearer <YOUR_API_KEY>' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"name": "updated_name",
|
||||
"search_config": {"top_k": 5}
|
||||
}'
|
||||
```
|
||||
|
||||
##### Request parameters
|
||||
|
||||
- `search_id`: (*Path parameter*), `string`, *Required*
|
||||
The ID of the search app to update.
|
||||
- `"name"`: (*Body parameter*), `string`, *Required*
|
||||
The new name of the search app.
|
||||
- `"search_config"`: (*Body parameter*), `object`, *Required*
|
||||
Configuration fields to update. Merged with the existing config.
|
||||
|
||||
#### Response
|
||||
|
||||
Success:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"id": "b330ec2e91ec11efbc510242ac120006",
|
||||
"name": "updated_name",
|
||||
"search_config": {"top_k": 5},
|
||||
"create_time": 1729763127646
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Failure:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 109,
|
||||
"message": "No authorization."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Delete search app
|
||||
|
||||
**DELETE** `/api/v1/searches/{search_id}`
|
||||
|
||||
Deletes a search app.
|
||||
|
||||
#### Request
|
||||
|
||||
- Method: DELETE
|
||||
- URL: `/api/v1/searches/{search_id}`
|
||||
- Headers:
|
||||
- `'Authorization: Bearer <YOUR_API_KEY>'`
|
||||
|
||||
##### Request example
|
||||
|
||||
```bash
|
||||
curl --request DELETE \
|
||||
--url 'http://{address}/api/v1/searches/b330ec2e91ec11efbc510242ac120006' \
|
||||
--header 'Authorization: Bearer <YOUR_API_KEY>'
|
||||
```
|
||||
|
||||
##### Request parameters
|
||||
|
||||
- `search_id`: (*Path parameter*), `string`, *Required*
|
||||
The ID of the search app to delete.
|
||||
|
||||
#### Response
|
||||
|
||||
Success:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": true
|
||||
}
|
||||
```
|
||||
|
||||
Failure:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 109,
|
||||
"message": "No authorization."
|
||||
}
|
||||
```
|
||||
|
||||
@ -379,7 +379,7 @@ def _select_first_dataset_and_save(
|
||||
return isinstance(kb_ids, list) and len(kb_ids) > 0
|
||||
|
||||
response_url_pattern = (
|
||||
"/dialog/set" if save_testid == "chat-settings-save" else "/search/update"
|
||||
"/dialog/set" if save_testid == "chat-settings-save" else "/api/v1/searches/"
|
||||
)
|
||||
last_payload = {}
|
||||
last_combobox_text = ""
|
||||
|
||||
@ -39,7 +39,7 @@ API_APP_URL = f"/{VERSION}/api"
|
||||
SYSTEM_APP_URL = f"/{VERSION}/system"
|
||||
LLM_APP_URL = f"/{VERSION}/llm"
|
||||
PLUGIN_APP_URL = f"/{VERSION}/plugin"
|
||||
SEARCH_APP_URL = f"/{VERSION}/search"
|
||||
SEARCHES_URL = f"/api/{VERSION}/searches"
|
||||
|
||||
|
||||
def _http_debug_enabled():
|
||||
@ -142,29 +142,27 @@ def plugin_llm_tools(auth, params=None, *, headers=HEADERS):
|
||||
|
||||
# SEARCH APP
|
||||
def search_create(auth, payload=None, *, headers=HEADERS, data=None):
|
||||
res = requests.post(url=f"{HOST_ADDRESS}{SEARCH_APP_URL}/create", headers=headers, auth=auth, json=payload, data=data)
|
||||
res = requests.post(url=f"{HOST_ADDRESS}{SEARCHES_URL}", headers=headers, auth=auth, json=payload, data=data)
|
||||
return res.json()
|
||||
|
||||
|
||||
def search_update(auth, payload=None, *, headers=HEADERS, data=None):
|
||||
res = requests.post(url=f"{HOST_ADDRESS}{SEARCH_APP_URL}/update", headers=headers, auth=auth, json=payload, data=data)
|
||||
def search_update(auth, search_id, payload=None, *, headers=HEADERS, data=None):
|
||||
res = requests.put(url=f"{HOST_ADDRESS}{SEARCHES_URL}/{search_id}", headers=headers, auth=auth, json=payload, data=data)
|
||||
return res.json()
|
||||
|
||||
|
||||
def search_detail(auth, params=None, *, headers=HEADERS):
|
||||
res = requests.get(url=f"{HOST_ADDRESS}{SEARCH_APP_URL}/detail", headers=headers, auth=auth, params=params)
|
||||
def search_detail(auth, search_id, *, headers=HEADERS):
|
||||
res = requests.get(url=f"{HOST_ADDRESS}{SEARCHES_URL}/{search_id}", headers=headers, auth=auth)
|
||||
return res.json()
|
||||
|
||||
|
||||
def search_list(auth, params=None, payload=None, *, headers=HEADERS, data=None):
|
||||
if payload is None:
|
||||
payload = {}
|
||||
res = requests.post(url=f"{HOST_ADDRESS}{SEARCH_APP_URL}/list", headers=headers, auth=auth, params=params, json=payload, data=data)
|
||||
def search_list(auth, params=None, *, headers=HEADERS):
|
||||
res = requests.get(url=f"{HOST_ADDRESS}{SEARCHES_URL}", headers=headers, auth=auth, params=params)
|
||||
return res.json()
|
||||
|
||||
|
||||
def search_rm(auth, payload=None, *, headers=HEADERS, data=None):
|
||||
res = requests.post(url=f"{HOST_ADDRESS}{SEARCH_APP_URL}/rm", headers=headers, auth=auth, json=payload, data=data)
|
||||
def search_rm(auth, search_id, *, headers=HEADERS):
|
||||
res = requests.delete(url=f"{HOST_ADDRESS}{SEARCHES_URL}/{search_id}", headers=headers, auth=auth)
|
||||
return res.json()
|
||||
|
||||
|
||||
|
||||
@ -31,15 +31,6 @@ def _search_name(prefix="search"):
|
||||
return f"{prefix}_{uuid.uuid4().hex[:8]}"
|
||||
|
||||
|
||||
def _find_tenant_id(WebApiAuth, search_id):
|
||||
res = search_list(WebApiAuth, payload={})
|
||||
assert res["code"] == 0, res
|
||||
for search_app in res["data"]["search_apps"]:
|
||||
if search_app.get("id") == search_id:
|
||||
return search_app.get("tenant_id")
|
||||
assert False, res
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def search_app(WebApiAuth):
|
||||
name = _search_name()
|
||||
@ -47,7 +38,7 @@ def search_app(WebApiAuth):
|
||||
assert create_res["code"] == 0, create_res
|
||||
search_id = create_res["data"]["search_id"]
|
||||
yield search_id
|
||||
rm_res = search_rm(WebApiAuth, {"search_id": search_id})
|
||||
rm_res = search_rm(WebApiAuth, search_id)
|
||||
assert rm_res["code"] == 0, rm_res
|
||||
assert rm_res["data"] is True, rm_res
|
||||
|
||||
@ -63,28 +54,28 @@ class TestAuthorization:
|
||||
@pytest.mark.p2
|
||||
@pytest.mark.parametrize("invalid_auth, expected_code, expected_fragment", INVALID_AUTH_CASES)
|
||||
def test_auth_invalid_list(self, invalid_auth, expected_code, expected_fragment):
|
||||
res = search_list(invalid_auth, payload={})
|
||||
res = search_list(invalid_auth)
|
||||
assert res["code"] == expected_code, res
|
||||
assert expected_fragment in res["message"], res
|
||||
|
||||
@pytest.mark.p2
|
||||
@pytest.mark.parametrize("invalid_auth, expected_code, expected_fragment", INVALID_AUTH_CASES)
|
||||
def test_auth_invalid_detail(self, invalid_auth, expected_code, expected_fragment):
|
||||
res = search_detail(invalid_auth, {"search_id": "dummy_search_id"})
|
||||
res = search_detail(invalid_auth, "dummy_search_id")
|
||||
assert res["code"] == expected_code, res
|
||||
assert expected_fragment in res["message"], res
|
||||
|
||||
@pytest.mark.p2
|
||||
@pytest.mark.parametrize("invalid_auth, expected_code, expected_fragment", INVALID_AUTH_CASES)
|
||||
def test_auth_invalid_update(self, invalid_auth, expected_code, expected_fragment):
|
||||
res = search_update(invalid_auth, {"search_id": "dummy", "name": "dummy", "search_config": {}, "tenant_id": "dummy"})
|
||||
res = search_update(invalid_auth, "dummy", {"name": "dummy", "search_config": {}})
|
||||
assert res["code"] == expected_code, res
|
||||
assert expected_fragment in res["message"], res
|
||||
|
||||
@pytest.mark.p2
|
||||
@pytest.mark.parametrize("invalid_auth, expected_code, expected_fragment", INVALID_AUTH_CASES)
|
||||
def test_auth_invalid_rm(self, invalid_auth, expected_code, expected_fragment):
|
||||
res = search_rm(invalid_auth, {"search_id": "dummy_search_id"})
|
||||
res = search_rm(invalid_auth, "dummy_search_id")
|
||||
assert res["code"] == expected_code, res
|
||||
assert expected_fragment in res["message"], res
|
||||
|
||||
@ -97,33 +88,26 @@ class TestSearchCrud:
|
||||
assert create_res["code"] == 0, create_res
|
||||
search_id = create_res["data"]["search_id"]
|
||||
|
||||
rm_res = search_rm(WebApiAuth, {"search_id": search_id})
|
||||
rm_res = search_rm(WebApiAuth, search_id)
|
||||
assert rm_res["code"] == 0, rm_res
|
||||
assert rm_res["data"] is True, rm_res
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_list(self, WebApiAuth, search_app):
|
||||
res = search_list(WebApiAuth, payload={})
|
||||
res = search_list(WebApiAuth)
|
||||
assert res["code"] == 0, res
|
||||
assert any(app.get("id") == search_app for app in res["data"]["search_apps"]), res
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_detail(self, WebApiAuth, search_app):
|
||||
res = search_detail(WebApiAuth, {"search_id": search_app})
|
||||
res = search_detail(WebApiAuth, search_app)
|
||||
assert res["code"] == 0, res
|
||||
assert res["data"].get("id") == search_app, res
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_update(self, WebApiAuth, search_app):
|
||||
tenant_id = _find_tenant_id(WebApiAuth, search_app)
|
||||
new_name = _search_name("updated")
|
||||
payload = {
|
||||
"search_id": search_app,
|
||||
"name": new_name,
|
||||
"search_config": {"top_k": 3},
|
||||
"tenant_id": tenant_id,
|
||||
}
|
||||
res = search_update(WebApiAuth, payload)
|
||||
res = search_update(WebApiAuth, search_app, {"name": new_name, "search_config": {"top_k": 3}})
|
||||
assert res["code"] == 0, res
|
||||
assert res["data"].get("name") == new_name, res
|
||||
|
||||
@ -138,17 +122,10 @@ class TestSearchCrud:
|
||||
create_res = search_create(WebApiAuth, {"name": _search_name("invalid"), "description": "test search"})
|
||||
assert create_res["code"] == 0, create_res
|
||||
search_id = create_res["data"]["search_id"]
|
||||
tenant_id = _find_tenant_id(WebApiAuth, search_id)
|
||||
try:
|
||||
payload = {
|
||||
"search_id": "invalid_search_id",
|
||||
"name": "invalid",
|
||||
"search_config": {},
|
||||
"tenant_id": tenant_id,
|
||||
}
|
||||
res = search_update(WebApiAuth, payload)
|
||||
res = search_update(WebApiAuth, "invalid_search_id", {"name": "invalid", "search_config": {}})
|
||||
assert res["code"] == 109, res
|
||||
assert "No authorization" in res["message"], res
|
||||
finally:
|
||||
rm_res = search_rm(WebApiAuth, {"search_id": search_id})
|
||||
rm_res = search_rm(WebApiAuth, search_id)
|
||||
assert rm_res["code"] == 0, rm_res
|
||||
|
||||
@ -44,6 +44,14 @@ class _Args(dict):
|
||||
def get(self, key, default=None):
|
||||
return super().get(key, default)
|
||||
|
||||
def getlist(self, key):
|
||||
val = self.get(key)
|
||||
if val is None:
|
||||
return []
|
||||
if isinstance(val, list):
|
||||
return val
|
||||
return [val]
|
||||
|
||||
|
||||
class _EnumValue:
|
||||
def __init__(self, value):
|
||||
@ -98,7 +106,7 @@ def set_tenant_info():
|
||||
return None
|
||||
|
||||
|
||||
def _load_search_app(monkeypatch):
|
||||
def _load_search_api(monkeypatch):
|
||||
repo_root = Path(__file__).resolve().parents[4]
|
||||
|
||||
quart_mod = ModuleType("quart")
|
||||
@ -233,23 +241,16 @@ def _load_search_app(monkeypatch):
|
||||
|
||||
return _decorator
|
||||
|
||||
def _not_allowed_parameters(*_params):
|
||||
def _decorator(func):
|
||||
return func
|
||||
|
||||
return _decorator
|
||||
|
||||
api_utils_mod.get_request_json = _default_request_json
|
||||
api_utils_mod.get_data_error_result = _get_data_error_result
|
||||
api_utils_mod.get_json_result = _get_json_result
|
||||
api_utils_mod.server_error_response = _server_error_response
|
||||
api_utils_mod.validate_request = _validate_request
|
||||
api_utils_mod.not_allowed_parameters = _not_allowed_parameters
|
||||
monkeypatch.setitem(sys.modules, "api.utils.api_utils", api_utils_mod)
|
||||
utils_pkg.api_utils = api_utils_mod
|
||||
|
||||
module_name = "test_search_routes_unit_module"
|
||||
module_path = repo_root / "api" / "apps" / "search_app.py"
|
||||
module_name = "test_search_api_unit_module"
|
||||
module_path = repo_root / "api" / "apps" / "restful_apis" / "search_api.py"
|
||||
spec = importlib.util.spec_from_file_location(module_name, module_path)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
module.manager = _DummyManager()
|
||||
@ -260,7 +261,7 @@ def _load_search_app(monkeypatch):
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_create_route_matrix_unit(monkeypatch):
|
||||
module = _load_search_app(monkeypatch)
|
||||
module = _load_search_api(monkeypatch)
|
||||
|
||||
_set_request_json(monkeypatch, module, {"name": 1})
|
||||
res = _run(module.create())
|
||||
@ -308,40 +309,46 @@ def test_create_route_matrix_unit(monkeypatch):
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_update_and_detail_route_matrix_unit(monkeypatch):
|
||||
module = _load_search_app(monkeypatch)
|
||||
module = _load_search_api(monkeypatch)
|
||||
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": 1, "search_config": {}, "tenant_id": "tenant-1"})
|
||||
res = _run(module.update())
|
||||
# update: name not string
|
||||
_set_request_json(monkeypatch, module, {"name": 1, "search_config": {}})
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "must be string" in res["message"]
|
||||
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": " ", "search_config": {}, "tenant_id": "tenant-1"})
|
||||
res = _run(module.update())
|
||||
# update: empty name
|
||||
_set_request_json(monkeypatch, module, {"name": " ", "search_config": {}})
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "empty" in res["message"].lower()
|
||||
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": "a" * 256, "search_config": {}, "tenant_id": "tenant-1"})
|
||||
res = _run(module.update())
|
||||
# update: name too long
|
||||
_set_request_json(monkeypatch, module, {"name": "a" * 256, "search_config": {}})
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "large than" in res["message"]
|
||||
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": "ok", "search_config": {}, "tenant_id": "tenant-1"})
|
||||
# update: tenant not found
|
||||
_set_request_json(monkeypatch, module, {"name": "ok", "search_config": {}})
|
||||
monkeypatch.setattr(module.TenantService, "get_by_id", lambda _tenant_id: (False, None))
|
||||
res = _run(module.update())
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "authorized identity" in res["message"].lower()
|
||||
|
||||
# update: no access
|
||||
monkeypatch.setattr(module.TenantService, "get_by_id", lambda _tenant_id: (True, SimpleNamespace(id=_tenant_id)))
|
||||
monkeypatch.setattr(module.SearchService, "accessible4deletion", lambda _search_id, _user_id: False)
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": "ok", "search_config": {}, "tenant_id": "tenant-1"})
|
||||
res = _run(module.update())
|
||||
_set_request_json(monkeypatch, module, {"name": "ok", "search_config": {}})
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.AUTHENTICATION_ERROR
|
||||
assert "authorization" in res["message"].lower()
|
||||
|
||||
# update: search not found (query returns [None])
|
||||
monkeypatch.setattr(module.SearchService, "accessible4deletion", lambda _search_id, _user_id: True)
|
||||
monkeypatch.setattr(module.SearchService, "query", lambda **_kwargs: [None])
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": "ok", "search_config": {}, "tenant_id": "tenant-1"})
|
||||
res = _run(module.update())
|
||||
_set_request_json(monkeypatch, module, {"name": "ok", "search_config": {}})
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "cannot find search" in res["message"].lower()
|
||||
|
||||
@ -354,18 +361,21 @@ def test_update_and_detail_route_matrix_unit(monkeypatch):
|
||||
return [SimpleNamespace(id="dup")]
|
||||
return []
|
||||
|
||||
# update: duplicate name
|
||||
monkeypatch.setattr(module.SearchService, "query", _query_duplicate)
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": "new-name", "search_config": {}, "tenant_id": "tenant-1"})
|
||||
res = _run(module.update())
|
||||
_set_request_json(monkeypatch, module, {"name": "new-name", "search_config": {}})
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "duplicated" in res["message"].lower()
|
||||
|
||||
# update: search_config not a dict
|
||||
monkeypatch.setattr(module.SearchService, "query", lambda **_kwargs: [existing])
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": "old-name", "search_config": [], "tenant_id": "tenant-1"})
|
||||
res = _run(module.update())
|
||||
_set_request_json(monkeypatch, module, {"name": "old-name", "search_config": []})
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "json object" in res["message"].lower()
|
||||
|
||||
# update: update_by_id fails, verifies config merge and field exclusion
|
||||
captured = {}
|
||||
|
||||
def _update_fail(search_id, req):
|
||||
@ -374,92 +384,96 @@ def test_update_and_detail_route_matrix_unit(monkeypatch):
|
||||
return False
|
||||
|
||||
monkeypatch.setattr(module.SearchService, "update_by_id", _update_fail)
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": "old-name", "search_config": {"top_k": 3}, "tenant_id": "tenant-1"})
|
||||
res = _run(module.update())
|
||||
_set_request_json(monkeypatch, module, {"name": "old-name", "search_config": {"top_k": 3}})
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "failed to update" in res["message"].lower()
|
||||
assert captured["search_id"] == "s1"
|
||||
assert "search_id" not in captured["req"]
|
||||
assert "tenant_id" not in captured["req"]
|
||||
assert captured["req"]["search_config"] == {"existing": 1, "top_k": 3}
|
||||
|
||||
# update: get_by_id fails after successful update
|
||||
monkeypatch.setattr(module.SearchService, "update_by_id", lambda _search_id, _req: True)
|
||||
monkeypatch.setattr(module.SearchService, "get_by_id", lambda _search_id: (False, None))
|
||||
res = _run(module.update())
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "failed to fetch" in res["message"].lower()
|
||||
|
||||
# update: success
|
||||
monkeypatch.setattr(
|
||||
module.SearchService,
|
||||
"get_by_id",
|
||||
lambda _search_id: (True, _SearchRecord(search_id=_search_id, name="old-name", search_config={"existing": 1, "top_k": 3})),
|
||||
)
|
||||
res = _run(module.update())
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == 0
|
||||
assert res["data"]["id"] == "s1"
|
||||
|
||||
# update: exception
|
||||
def _raise_query(**_kwargs):
|
||||
raise RuntimeError("update boom")
|
||||
|
||||
monkeypatch.setattr(module.SearchService, "query", _raise_query)
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": "old-name", "search_config": {"top_k": 3}, "tenant_id": "tenant-1"})
|
||||
res = _run(module.update())
|
||||
_set_request_json(monkeypatch, module, {"name": "old-name", "search_config": {"top_k": 3}})
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.EXCEPTION_ERROR
|
||||
assert "update boom" in res["message"]
|
||||
|
||||
_set_request_args(monkeypatch, module, {"search_id": "s1"})
|
||||
# detail: no permission
|
||||
monkeypatch.setattr(module.UserTenantService, "query", lambda **_kwargs: [SimpleNamespace(tenant_id="tenant-a")])
|
||||
monkeypatch.setattr(module.SearchService, "query", lambda **_kwargs: [])
|
||||
res = module.detail()
|
||||
res = module.detail(search_id="s1")
|
||||
assert res["code"] == module.RetCode.OPERATING_ERROR
|
||||
assert "permission" in res["message"].lower()
|
||||
|
||||
# detail: search not found
|
||||
monkeypatch.setattr(module.SearchService, "query", lambda **_kwargs: [SimpleNamespace(id="s1")])
|
||||
monkeypatch.setattr(module.SearchService, "get_detail", lambda _search_id: None)
|
||||
res = module.detail()
|
||||
res = module.detail(search_id="s1")
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "can't find" in res["message"].lower()
|
||||
|
||||
# detail: success
|
||||
monkeypatch.setattr(module.SearchService, "get_detail", lambda _search_id: {"id": _search_id, "name": "detail-name"})
|
||||
res = module.detail()
|
||||
res = module.detail(search_id="s1")
|
||||
assert res["code"] == 0
|
||||
assert res["data"]["id"] == "s1"
|
||||
|
||||
# detail: exception
|
||||
def _raise_detail(_search_id):
|
||||
raise RuntimeError("detail boom")
|
||||
|
||||
monkeypatch.setattr(module.SearchService, "get_detail", _raise_detail)
|
||||
res = module.detail()
|
||||
res = module.detail(search_id="s1")
|
||||
assert res["code"] == module.RetCode.EXCEPTION_ERROR
|
||||
assert "detail boom" in res["message"]
|
||||
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_list_and_rm_route_matrix_unit(monkeypatch):
|
||||
module = _load_search_app(monkeypatch)
|
||||
def test_list_and_delete_route_matrix_unit(monkeypatch):
|
||||
module = _load_search_api(monkeypatch)
|
||||
|
||||
# list: no owner_ids, with pagination
|
||||
_set_request_args(
|
||||
monkeypatch,
|
||||
module,
|
||||
{"keywords": "k", "page": "1", "page_size": "2", "orderby": "create_time", "desc": "false"},
|
||||
)
|
||||
_set_request_json(monkeypatch, module, {"owner_ids": []})
|
||||
monkeypatch.setattr(
|
||||
module.SearchService,
|
||||
"get_by_tenant_ids",
|
||||
lambda _tenants, _uid, _page, _size, _orderby, _desc, _keywords: ([{"id": "a", "tenant_id": "tenant-1"}], 1),
|
||||
)
|
||||
res = _run(module.list_search_app())
|
||||
res = module.list_searches()
|
||||
assert res["code"] == 0
|
||||
assert res["data"]["total"] == 1
|
||||
assert res["data"]["search_apps"][0]["id"] == "a"
|
||||
|
||||
# list: with owner_ids filter and pagination
|
||||
_set_request_args(
|
||||
monkeypatch,
|
||||
module,
|
||||
{"keywords": "k", "page": "1", "page_size": "1", "orderby": "create_time", "desc": "true"},
|
||||
{"keywords": "k", "page": "1", "page_size": "1", "orderby": "create_time", "desc": "true", "owner_ids": ["tenant-1"]},
|
||||
)
|
||||
_set_request_json(monkeypatch, module, {"owner_ids": ["tenant-1"]})
|
||||
monkeypatch.setattr(
|
||||
module.SearchService,
|
||||
"get_by_tenant_ids",
|
||||
@ -468,42 +482,46 @@ def test_list_and_rm_route_matrix_unit(monkeypatch):
|
||||
2,
|
||||
),
|
||||
)
|
||||
res = _run(module.list_search_app())
|
||||
res = module.list_searches()
|
||||
assert res["code"] == 0
|
||||
assert res["data"]["total"] == 1
|
||||
assert len(res["data"]["search_apps"]) == 1
|
||||
assert res["data"]["search_apps"][0]["tenant_id"] == "tenant-1"
|
||||
|
||||
# list: exception
|
||||
def _raise_list(*_args, **_kwargs):
|
||||
raise RuntimeError("list boom")
|
||||
|
||||
monkeypatch.setattr(module.SearchService, "get_by_tenant_ids", _raise_list)
|
||||
_set_request_json(monkeypatch, module, {"owner_ids": []})
|
||||
res = _run(module.list_search_app())
|
||||
_set_request_args(monkeypatch, module, {})
|
||||
res = module.list_searches()
|
||||
assert res["code"] == module.RetCode.EXCEPTION_ERROR
|
||||
assert "list boom" in res["message"]
|
||||
|
||||
_set_request_json(monkeypatch, module, {"search_id": "search-1"})
|
||||
# delete: no authorization
|
||||
monkeypatch.setattr(module.SearchService, "accessible4deletion", lambda _search_id, _user_id: False)
|
||||
res = _run(module.rm())
|
||||
res = module.delete_search(search_id="search-1")
|
||||
assert res["code"] == module.RetCode.AUTHENTICATION_ERROR
|
||||
assert "authorization" in res["message"].lower()
|
||||
|
||||
# delete: delete_by_id fails
|
||||
monkeypatch.setattr(module.SearchService, "accessible4deletion", lambda _search_id, _user_id: True)
|
||||
monkeypatch.setattr(module.SearchService, "delete_by_id", lambda _search_id: False)
|
||||
res = _run(module.rm())
|
||||
res = module.delete_search(search_id="search-1")
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "failed to delete" in res["message"].lower()
|
||||
|
||||
# delete: success
|
||||
monkeypatch.setattr(module.SearchService, "delete_by_id", lambda _search_id: True)
|
||||
res = _run(module.rm())
|
||||
res = module.delete_search(search_id="search-1")
|
||||
assert res["code"] == 0
|
||||
assert res["data"] is True
|
||||
|
||||
# delete: exception
|
||||
def _raise_delete(_search_id):
|
||||
raise RuntimeError("rm boom")
|
||||
|
||||
monkeypatch.setattr(module.SearchService, "delete_by_id", _raise_delete)
|
||||
res = _run(module.rm())
|
||||
res = module.delete_search(search_id="search-1")
|
||||
assert res["code"] == module.RetCode.EXCEPTION_ERROR
|
||||
assert "rm boom" in res["message"]
|
||||
|
||||
@ -4,7 +4,7 @@ import message from '@/components/ui/message';
|
||||
import { useSetModalState } from '@/hooks/common-hooks';
|
||||
import { useHandleSearchChange } from '@/hooks/logic-hooks';
|
||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||
import searchService, { searchServiceNext } from '@/services/search-service';
|
||||
import searchService from '@/services/search-service';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useDebounce } from 'ahooks';
|
||||
import { useCallback, useState } from 'react';
|
||||
@ -103,14 +103,13 @@ export const useFetchSearchList = () => {
|
||||
},
|
||||
],
|
||||
queryFn: async () => {
|
||||
const { data: response } = await searchServiceNext.getSearchList(
|
||||
const { data: response } = await searchService.getSearchList(
|
||||
{
|
||||
params: {
|
||||
keywords: debouncedSearchString,
|
||||
page_size: pagination.pageSize,
|
||||
page: pagination.current,
|
||||
},
|
||||
data: {},
|
||||
},
|
||||
true,
|
||||
);
|
||||
@ -203,24 +202,21 @@ export const useFetchSearchDetail = (tenantId?: string) => {
|
||||
const [searchParams] = useSearchParams();
|
||||
const shared_id = searchParams.get('shared_id');
|
||||
const searchId = id || shared_id;
|
||||
let param: { search_id: string | null; tenant_id?: string } = {
|
||||
search_id: searchId,
|
||||
};
|
||||
if (shared_id) {
|
||||
param = {
|
||||
search_id: searchId,
|
||||
tenant_id: tenantId,
|
||||
};
|
||||
}
|
||||
const fetchSearchDetailFunc = shared_id
|
||||
? searchService.getSearchDetailShare
|
||||
: searchService.getSearchDetail;
|
||||
|
||||
const { data, isLoading, isError } = useQuery<SearchDetailResponse, Error>({
|
||||
queryKey: ['searchDetail', searchId],
|
||||
enabled: !shared_id || !!tenantId,
|
||||
queryFn: async () => {
|
||||
const { data: response } = await fetchSearchDetailFunc(param);
|
||||
let res;
|
||||
if (shared_id) {
|
||||
res = await searchService.getSearchDetailShare(
|
||||
{ params: { search_id: searchId, tenant_id: tenantId } },
|
||||
true,
|
||||
);
|
||||
} else {
|
||||
res = await searchService.getSearchDetail({ search_id: searchId });
|
||||
}
|
||||
const response = res.data;
|
||||
if (response.code !== 0) {
|
||||
throw new Error(response.message || 'Failed to fetch search detail');
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import api from '@/utils/api';
|
||||
import registerServer, { registerNextServer } from '@/utils/register-server';
|
||||
import request from '@/utils/request';
|
||||
import { registerNextServer } from '@/utils/register-server';
|
||||
|
||||
const {
|
||||
createSearch,
|
||||
@ -13,6 +12,7 @@ const {
|
||||
getRelatedQuestionsShare,
|
||||
getSearchDetailShare,
|
||||
} = api;
|
||||
|
||||
const methods = {
|
||||
createSearch: {
|
||||
url: createSearch,
|
||||
@ -20,16 +20,16 @@ const methods = {
|
||||
},
|
||||
getSearchList: {
|
||||
url: getSearchList,
|
||||
method: 'post',
|
||||
method: 'get',
|
||||
},
|
||||
deleteSearch: { url: deleteSearch, method: 'post' },
|
||||
deleteSearch: { url: deleteSearch, method: 'delete' },
|
||||
getSearchDetail: {
|
||||
url: getSearchDetail,
|
||||
method: 'get',
|
||||
},
|
||||
updateSearchSetting: {
|
||||
url: updateSearchSetting,
|
||||
method: 'post',
|
||||
method: 'put',
|
||||
},
|
||||
askShare: {
|
||||
url: askShare,
|
||||
@ -43,14 +43,13 @@ const methods = {
|
||||
url: getRelatedQuestionsShare,
|
||||
method: 'post',
|
||||
},
|
||||
|
||||
getSearchDetailShare: {
|
||||
url: getSearchDetailShare,
|
||||
method: 'get',
|
||||
},
|
||||
} as const;
|
||||
const searchService = registerServer<keyof typeof methods>(methods, request);
|
||||
export const searchServiceNext =
|
||||
registerNextServer<keyof typeof methods>(methods);
|
||||
|
||||
const searchService = registerNextServer<keyof typeof methods>(methods);
|
||||
export const searchServiceNext = searchService;
|
||||
|
||||
export default searchService;
|
||||
|
||||
@ -237,12 +237,15 @@ export default {
|
||||
testMcpServer: `${api_host}/mcp_server/test_mcp`,
|
||||
|
||||
// next-search
|
||||
createSearch: `${api_host}/search/create`,
|
||||
getSearchList: `${api_host}/search/list`,
|
||||
deleteSearch: `${api_host}/search/rm`,
|
||||
getSearchDetail: `${api_host}/search/detail`,
|
||||
createSearch: `${ExternalApi}${api_host}/searches`,
|
||||
getSearchList: `${ExternalApi}${api_host}/searches`,
|
||||
deleteSearch: (params: { search_id: string }) =>
|
||||
`${ExternalApi}${api_host}/searches/${params.search_id}`,
|
||||
getSearchDetail: (params: { search_id: string }) =>
|
||||
`${ExternalApi}${api_host}/searches/${params.search_id}`,
|
||||
getSearchDetailShare: `${ExternalApi}${api_host}/searchbots/detail`,
|
||||
updateSearchSetting: `${api_host}/search/update`,
|
||||
updateSearchSetting: (params: { search_id: string }) =>
|
||||
`${ExternalApi}${api_host}/searches/${params.search_id}`,
|
||||
askShare: `${ExternalApi}${api_host}/searchbots/ask`,
|
||||
mindmapShare: `${ExternalApi}${api_host}/searchbots/mindmap`,
|
||||
getRelatedQuestionsShare: `${ExternalApi}${api_host}/searchbots/related_questions`,
|
||||
|
||||
@ -82,7 +82,7 @@ const API_WHITELIST = [
|
||||
'/v1/dialog/set',
|
||||
'/v1/canvas/set',
|
||||
'/v1/canvas/setting',
|
||||
'/v1/search/update',
|
||||
'/api/v1/searches/',
|
||||
'/api/v1/memories',
|
||||
'/v1/kb/create',
|
||||
'/v1/kb/update',
|
||||
|
||||
Reference in New Issue
Block a user