mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-13 04:14:42 +00:00
fix(feedback): accept widget api_key on /api/feedback
This commit is contained in:
1 parent
74e26cde1e
commit
57e6836ec0
2 files changed
+102
-3
No files matched your search
@@ -11,6 +11,7 @@ from application.api.answer.services.conversation_service import (
|
||||
TERMINATED_RESPONSE_PLACEHOLDER,
|
||||
)
|
||||
from application.storage.db.base_repository import looks_like_uuid, row_to_dict
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from application.storage.db.repositories.attachments import AttachmentsRepository
|
||||
from application.storage.db.repositories.conversations import ConversationsRepository
|
||||
from application.storage.db.repositories.message_events import MessageEventsRepository
|
||||
@@ -357,10 +358,20 @@ class SubmitFeedback(Resource):
|
||||
description="Submit feedback for a conversation",
|
||||
)
|
||||
def post(self):
|
||||
data = request.get_json() or {}
|
||||
decoded_token = request.decoded_token
|
||||
# api_key callers (widgets) carry no JWT; resolve the key to its owner.
|
||||
scoped_api_key = None
|
||||
if not decoded_token:
|
||||
return make_response(jsonify({"success": False}), 401)
|
||||
data = request.get_json()
|
||||
api_key = data.get("api_key")
|
||||
agent = None
|
||||
if api_key:
|
||||
with db_readonly() as conn:
|
||||
agent = AgentsRepository(conn).find_by_key(api_key)
|
||||
if not agent:
|
||||
return make_response(jsonify({"success": False}), 401)
|
||||
decoded_token = {"sub": agent.get("user_id")}
|
||||
scoped_api_key = api_key
|
||||
required_fields = ["feedback", "conversation_id", "question_index"]
|
||||
missing_fields = check_required_fields(data, required_fields)
|
||||
if missing_fields:
|
||||
@@ -387,7 +398,10 @@ class SubmitFeedback(Resource):
|
||||
with db_session() as conn:
|
||||
repo = ConversationsRepository(conn)
|
||||
conv = repo.get_any(data["conversation_id"], user_id)
|
||||
if conv is None:
|
||||
# A key may only rate conversations it created.
|
||||
if conv is None or (
|
||||
scoped_api_key and conv.get("api_key") != scoped_api_key
|
||||
):
|
||||
return make_response(
|
||||
jsonify({"success": False, "message": "Not found"}), 404
|
||||
)
|
||||
|
||||
@@ -769,3 +769,88 @@ class TestSubmitFeedbackHappy:
|
||||
response = SubmitFeedback().post()
|
||||
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestSubmitFeedbackWithApiKey:
|
||||
"""api_key callers carry no JWT."""
|
||||
|
||||
def _seed_agent_with_key(self, pg_conn, owner, key):
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
return AgentsRepository(pg_conn).create(owner, "widget", "published", key=key)
|
||||
|
||||
def _post(self, app, pg_conn, payload):
|
||||
from application.api.user.conversations.routes import SubmitFeedback
|
||||
|
||||
with _patch_conversations_db(pg_conn), app.test_request_context("/api/feedback", method="POST", json=payload):
|
||||
from flask import request
|
||||
|
||||
request.decoded_token = None
|
||||
return SubmitFeedback().post()
|
||||
|
||||
def test_valid_key_rates_its_own_conversation(self, app, pg_conn):
|
||||
from application.storage.db.repositories.conversations import (
|
||||
ConversationsRepository,
|
||||
)
|
||||
|
||||
owner, key = "owner-fb-key", "agent-key-ok"
|
||||
self._seed_agent_with_key(pg_conn, owner, key)
|
||||
repo = ConversationsRepository(pg_conn)
|
||||
conv_id = str(repo.create(owner, name="via widget", api_key=key)["id"])
|
||||
repo.append_message(conv_id, {"prompt": "p", "response": "r"})
|
||||
|
||||
response = self._post(
|
||||
app,
|
||||
pg_conn,
|
||||
{
|
||||
"feedback": "LIKE",
|
||||
"question_index": 0,
|
||||
"conversation_id": conv_id,
|
||||
"api_key": key,
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
fb = repo.get_messages(conv_id)[0].get("feedback")
|
||||
assert fb and fb.get("text") == "like"
|
||||
|
||||
def test_key_cannot_rate_owner_conversation_it_did_not_create(self, app, pg_conn):
|
||||
from application.storage.db.repositories.conversations import (
|
||||
ConversationsRepository,
|
||||
)
|
||||
|
||||
owner, key = "owner-fb-scope", "agent-key-scope"
|
||||
self._seed_agent_with_key(pg_conn, owner, key)
|
||||
# Owner's conversation, not created with the key.
|
||||
conv_id = _seed_conversation(pg_conn, owner, name="owner private")
|
||||
ConversationsRepository(pg_conn).append_message(conv_id, {"prompt": "p", "response": "r"})
|
||||
|
||||
response = self._post(
|
||||
app,
|
||||
pg_conn,
|
||||
{
|
||||
"feedback": "LIKE",
|
||||
"question_index": 0,
|
||||
"conversation_id": conv_id,
|
||||
"api_key": key,
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_unknown_key_is_unauthorized(self, app, pg_conn):
|
||||
conv_id = _seed_conversation(pg_conn, "owner-fb-bad")
|
||||
|
||||
response = self._post(
|
||||
app,
|
||||
pg_conn,
|
||||
{
|
||||
"feedback": "LIKE",
|
||||
"question_index": 0,
|
||||
"conversation_id": conv_id,
|
||||
"api_key": "no-such-key",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 401
|
||||
Reference in new issue
Block a user