Skip to content

Commit 77e4f46

Browse files
authored
Merge pull request #133 from agent-diff-bench/fixes-kdd
Perff
2 parents f1e24a3 + 5e5bece commit 77e4f46

2 files changed

Lines changed: 205 additions & 0 deletions

File tree

backend/src/platform/isolationEngine/environment.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,38 @@ def migrate_schema(self, template_schema: str, target_schema: str) -> None:
4444
)
4545
meta.create_all(translated)
4646

47+
# Ensure newer columns exist even if template was seeded before they
48+
# were added to the ORM models. Uses IF NOT EXISTS so it's safe to
49+
# run repeatedly.
50+
self._ensure_box_columns(target_schema)
51+
4752
# Copy GIN / non-standard indexes that MetaData.reflect doesn't capture
4853
self._copy_custom_indexes(template_schema, target_schema)
4954

5055
self._set_replica_identity(target_schema)
5156

57+
def _ensure_box_columns(self, schema: str) -> None:
58+
"""Add columns that may be missing from older template snapshots."""
59+
_columns = [
60+
# (table, column, SQL type, default)
61+
("box_folders", "path", "VARCHAR(500)", "'/'"),
62+
("box_files", "path", "VARCHAR(500)", "'/0/'"),
63+
]
64+
with self.session_manager.base_engine.begin() as conn:
65+
for table, col, sql_type, default in _columns:
66+
try:
67+
conn.execute(
68+
text(
69+
f"ALTER TABLE {schema}.{table} "
70+
f"ADD COLUMN IF NOT EXISTS {col} {sql_type} "
71+
f"DEFAULT {default}"
72+
)
73+
)
74+
except Exception as exc:
75+
logger.warning(
76+
f"Could not ensure column {schema}.{table}.{col}: {exc}"
77+
)
78+
5279
def _copy_custom_indexes(self, src_schema: str, dst_schema: str) -> None:
5380
"""Copy GIN trigram and other custom indexes from template to target schema."""
5481
with self.session_manager.base_engine.begin() as conn:

backend/src/services/box/api/routes.py

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,6 +1429,82 @@ async def list_file_comments(request: Request) -> Response:
14291429
return _error_response(e)
14301430

14311431

1432+
async def get_comment_by_id(request: Request) -> Response:
1433+
"""
1434+
GET /2.0/comments/{comment_id}
1435+
1436+
Retrieves a specific comment.
1437+
1438+
SDK Reference: CommentsManager.get_comment_by_id()
1439+
"""
1440+
try:
1441+
session = _session(request)
1442+
comment_id = request.path_params["comment_id"]
1443+
fields = _parse_fields(request)
1444+
1445+
comment = ops.get_comment_by_id(session, comment_id)
1446+
if not comment:
1447+
_box_error(BoxErrorCode.NOT_FOUND, "Not Found")
1448+
1449+
comment_data = comment.to_dict()
1450+
filtered_data = _filter_fields(comment_data, fields)
1451+
1452+
return _json_response(filtered_data)
1453+
1454+
except BoxAPIError as e:
1455+
return _error_response(e)
1456+
1457+
1458+
async def update_comment_by_id(request: Request) -> Response:
1459+
"""
1460+
PUT /2.0/comments/{comment_id}
1461+
1462+
Updates a comment's message.
1463+
1464+
SDK Reference: CommentsManager.update_comment_by_id()
1465+
"""
1466+
try:
1467+
session = _session(request)
1468+
comment_id = request.path_params["comment_id"]
1469+
fields = _parse_fields(request)
1470+
1471+
body = await _parse_json_body(request)
1472+
message = body.get("message")
1473+
1474+
comment = ops.update_comment(session, comment_id, message=message)
1475+
1476+
comment_data = comment.to_dict()
1477+
filtered_data = _filter_fields(comment_data, fields)
1478+
1479+
return _json_response(filtered_data)
1480+
1481+
except BoxAPIError as e:
1482+
return _error_response(e)
1483+
1484+
1485+
async def delete_comment_by_id(request: Request) -> Response:
1486+
"""
1487+
DELETE /2.0/comments/{comment_id}
1488+
1489+
Deletes a comment.
1490+
1491+
SDK Reference: CommentsManager.delete_comment_by_id()
1492+
1493+
Returns:
1494+
204 No Content on success
1495+
"""
1496+
try:
1497+
session = _session(request)
1498+
comment_id = request.path_params["comment_id"]
1499+
1500+
ops.delete_comment(session, comment_id)
1501+
1502+
return Response(status_code=status.HTTP_204_NO_CONTENT)
1503+
1504+
except BoxAPIError as e:
1505+
return _error_response(e)
1506+
1507+
14321508
# Task Endpoints
14331509

14341510

@@ -1567,6 +1643,102 @@ async def create_task(request: Request) -> Response:
15671643
return _error_response(e)
15681644

15691645

1646+
async def get_task_by_id(request: Request) -> Response:
1647+
"""
1648+
GET /2.0/tasks/{task_id}
1649+
1650+
Retrieves a specific task.
1651+
1652+
SDK Reference: TasksManager.get_task_by_id()
1653+
"""
1654+
try:
1655+
session = _session(request)
1656+
task_id = request.path_params["task_id"]
1657+
fields = _parse_fields(request)
1658+
1659+
task = ops.get_task_by_id(session, task_id)
1660+
if not task:
1661+
_box_error(BoxErrorCode.NOT_FOUND, "Not Found")
1662+
1663+
task_data = task.to_dict()
1664+
filtered_data = _filter_fields(task_data, fields)
1665+
1666+
return _json_response(filtered_data)
1667+
1668+
except BoxAPIError as e:
1669+
return _error_response(e)
1670+
1671+
1672+
async def update_task_by_id(request: Request) -> Response:
1673+
"""
1674+
PUT /2.0/tasks/{task_id}
1675+
1676+
Updates a task.
1677+
1678+
SDK Reference: TasksManager.update_task_by_id()
1679+
"""
1680+
try:
1681+
session = _session(request)
1682+
task_id = request.path_params["task_id"]
1683+
fields = _parse_fields(request)
1684+
1685+
body = await _parse_json_body(request)
1686+
1687+
action = body.get("action")
1688+
message = body.get("message")
1689+
due_at_str = body.get("due_at")
1690+
completion_rule = body.get("completion_rule")
1691+
1692+
due_at = None
1693+
if due_at_str:
1694+
from datetime import datetime
1695+
1696+
try:
1697+
due_at = datetime.fromisoformat(due_at_str.replace("Z", "+00:00"))
1698+
except (ValueError, AttributeError):
1699+
_box_error(BoxErrorCode.BAD_REQUEST, "Invalid 'due_at' format")
1700+
1701+
task = ops.update_task(
1702+
session,
1703+
task_id,
1704+
action=action,
1705+
message=message,
1706+
due_at=due_at,
1707+
completion_rule=completion_rule,
1708+
)
1709+
1710+
task_data = task.to_dict()
1711+
filtered_data = _filter_fields(task_data, fields)
1712+
1713+
return _json_response(filtered_data)
1714+
1715+
except BoxAPIError as e:
1716+
return _error_response(e)
1717+
1718+
1719+
async def delete_task_by_id(request: Request) -> Response:
1720+
"""
1721+
DELETE /2.0/tasks/{task_id}
1722+
1723+
Deletes a task.
1724+
1725+
SDK Reference: TasksManager.delete_task_by_id()
1726+
1727+
Returns:
1728+
204 No Content on success
1729+
"""
1730+
try:
1731+
session = _session(request)
1732+
task_id = request.path_params["task_id"]
1733+
1734+
ops.delete_task(session, task_id)
1735+
1736+
return Response(status_code=status.HTTP_204_NO_CONTENT)
1737+
1738+
except BoxAPIError as e:
1739+
return _error_response(e)
1740+
1741+
15701742
# Hub Endpoints (Requires box-version: 2025.0 header)
15711743

15721744

@@ -2079,8 +2251,14 @@ async def get_collection_items(request: Request) -> Response:
20792251
Route("/files/{file_id}/tasks", list_file_tasks, methods=["GET"]),
20802252
# Comments
20812253
Route("/comments", create_comment, methods=["POST"]),
2254+
Route("/comments/{comment_id}", get_comment_by_id, methods=["GET"]),
2255+
Route("/comments/{comment_id}", update_comment_by_id, methods=["PUT"]),
2256+
Route("/comments/{comment_id}", delete_comment_by_id, methods=["DELETE"]),
20822257
# Tasks
20832258
Route("/tasks", create_task, methods=["POST"]),
2259+
Route("/tasks/{task_id}", get_task_by_id, methods=["GET"]),
2260+
Route("/tasks/{task_id}", update_task_by_id, methods=["PUT"]),
2261+
Route("/tasks/{task_id}", delete_task_by_id, methods=["DELETE"]),
20842262
# Hubs (requires box-version: 2025.0 header)
20852263
Route("/hubs", list_hubs, methods=["GET"]),
20862264
Route("/hubs", create_hub, methods=["POST"]),

0 commit comments

Comments
 (0)