Add Request Changes feature for admin tool moderation
- Add POST /api/v1/admin/tools/{id}/request-changes endpoint
- Sets moderation_status to 'changes_requested' with feedback
- Extend /me/tools/{name}/status to return feedback when status is
changes_requested or rejected
- Add Request Changes button and modal in admin pending UI
- Make changes modal draggable like other modals
This allows admins to send feedback to publishers instead of just
approving or rejecting tools outright.
Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit is contained in:
@@ -2001,7 +2001,7 @@ def create_app() -> Flask:
|
||||
row = query_one(
|
||||
g.db,
|
||||
"""
|
||||
SELECT name, version, moderation_status, config_hash, published_at
|
||||
SELECT name, version, moderation_status, moderation_note, config_hash, published_at
|
||||
FROM tools
|
||||
WHERE owner = ? AND name = ?
|
||||
ORDER BY published_at DESC
|
||||
@@ -2013,15 +2013,19 @@ def create_app() -> Flask:
|
||||
if not row:
|
||||
return error_response("TOOL_NOT_FOUND", f"Tool '{name}' not found", 404)
|
||||
|
||||
return jsonify({
|
||||
"data": {
|
||||
"name": row["name"],
|
||||
"version": row["version"],
|
||||
"status": row["moderation_status"],
|
||||
"config_hash": row["config_hash"],
|
||||
"published_at": row["published_at"],
|
||||
}
|
||||
})
|
||||
result = {
|
||||
"name": row["name"],
|
||||
"version": row["version"],
|
||||
"status": row["moderation_status"],
|
||||
"config_hash": row["config_hash"],
|
||||
"published_at": row["published_at"],
|
||||
}
|
||||
|
||||
# Include feedback if status is changes_requested or rejected
|
||||
if row["moderation_status"] in ("changes_requested", "rejected") and row["moderation_note"]:
|
||||
result["feedback"] = row["moderation_note"]
|
||||
|
||||
return jsonify({"data": result})
|
||||
|
||||
@app.route("/api/v1/tools/<owner>/<name>/deprecate", methods=["POST"])
|
||||
@require_token
|
||||
@@ -2665,6 +2669,41 @@ def create_app() -> Flask:
|
||||
|
||||
return jsonify({"data": {"status": "rejected", "tool_id": tool_id}})
|
||||
|
||||
@app.route("/api/v1/admin/tools/<int:tool_id>/request-changes", methods=["POST"])
|
||||
@require_moderator
|
||||
def admin_request_changes(tool_id: int) -> Response:
|
||||
"""Request changes from tool publisher before approval."""
|
||||
data = request.get_json() or {}
|
||||
feedback = (data.get("feedback") or data.get("reason") or "").strip()
|
||||
|
||||
if not feedback:
|
||||
return error_response("VALIDATION_ERROR", "Feedback is required", 400)
|
||||
|
||||
tool = query_one(g.db, "SELECT * FROM tools WHERE id = ?", [tool_id])
|
||||
if not tool:
|
||||
return error_response("TOOL_NOT_FOUND", "Tool not found", 404)
|
||||
|
||||
g.db.execute(
|
||||
"""
|
||||
UPDATE tools
|
||||
SET moderation_status = 'changes_requested',
|
||||
moderation_note = ?,
|
||||
moderated_by = ?,
|
||||
moderated_at = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
[feedback, g.current_publisher["slug"], datetime.utcnow().isoformat(), tool_id],
|
||||
)
|
||||
g.db.commit()
|
||||
|
||||
log_audit("request_changes", "tool", str(tool_id), {
|
||||
"tool": f"{tool['owner']}/{tool['name']}",
|
||||
"version": tool["version"],
|
||||
"feedback": feedback[:200], # Truncate for audit log
|
||||
})
|
||||
|
||||
return jsonify({"data": {"status": "changes_requested", "tool_id": tool_id}})
|
||||
|
||||
@app.route("/api/v1/admin/scrutiny", methods=["GET"])
|
||||
@require_moderator
|
||||
def admin_scrutiny_audit() -> Response:
|
||||
|
||||
Reference in New Issue
Block a user