fix(feedback): accept widget api_key on /api/feedback

This commit is contained in:
ManishMadan2882 committed 2026-08-30 06:25:28 +05:30
1 parent 74e26cde1e
commit 57e6836ec0
2 files changed
+102 -3

No files matched your search

+17 -3
View File
@@ -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
)
+85
View File
@@ -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