refactor(http): drop categories/subcategories shim

Remove the transitional layer added in commits 1+2:

models.py
  - Drop Category, Subcategory, CreateCategory, CreateSubcategory.

crud.py
  - Drop create_category / update_category / get_category /
    get_categories / delete_category and the subcategory variants
    along with the _node_row_to_category / _node_row_to_subcategory
    helpers. Tree state is owned exclusively by menu_node CRUD now.

views_api.py
  - Remove old endpoints:
      GET    /api/v1/restaurants/{id}/categories
      POST   /api/v1/categories
      DELETE /api/v1/categories/{id}
      GET    /api/v1/categories/{id}/subcategories
      POST   /api/v1/subcategories
      DELETE /api/v1/subcategories/{id}
    Hits return 404 now.
  - GET /api/v1/restaurants/{id}/menu loses the synthetic
    'categories' projection. Response is {restaurant, tree, items}.

static/js/api.js
  - Drop listCategories / createCategory / deleteCategory and the
    subcategory wrappers.

The CMS menu builder is broken between this commit and commit 4.
The plan acknowledged this trade-off: keeping commits revertible
beats the cost of an unshipped UI page rendering a stale empty
sidebar for one commit's lifetime.
This commit is contained in:
Padreug 2026-05-02 09:08:01 +02:00
commit b7fa1aec4a
4 changed files with 8 additions and 300 deletions

127
crud.py
View file

@ -21,15 +21,12 @@ from lnbits.helpers import urlsafe_short_hash
from .models import (
MAX_MENU_DEPTH,
AvailabilityWindow,
Category,
CreateAvailabilityWindow,
CreateCategory,
CreateMenuItem,
CreateMenuNode,
CreateModifier,
CreateModifierGroup,
CreateRestaurant,
CreateSubcategory,
MenuItem,
MenuNode,
MenuNodeRow,
@ -41,7 +38,6 @@ from .models import (
Restaurant,
RestaurantSettings,
SelectedModifier,
Subcategory,
)
db = Database("ext_restaurant")
@ -397,129 +393,6 @@ async def delete_menu_node(node_id: str, cascade: bool = False) -> None:
)
# --------------------------------------------------------------------- #
# Categories / subcategories — transitional shims (drop in commit 3) #
# --------------------------------------------------------------------- #
# These keep the old /categories and /subcategories REST endpoints
# working over the new menu_nodes table for one commit's lifetime.
# Drop entirely in the next commit once the new endpoints are live.
def _node_row_to_category(row: MenuNodeRow) -> Category:
return Category(
id=row.id,
restaurant_id=row.restaurant_id,
name=row.name,
description=row.description,
sort_order=row.sort_order,
image_url=row.image_url,
time=row.time,
)
def _node_row_to_subcategory(row: MenuNodeRow) -> Subcategory:
# Subcategory carries the parent category id, not its own restaurant.
return Subcategory(
id=row.id,
category_id=row.parent_id or "",
name=row.name,
sort_order=row.sort_order,
time=row.time,
)
async def create_category(data: CreateCategory) -> Category:
node = await create_menu_node(
CreateMenuNode(
restaurant_id=data.restaurant_id,
parent_id=None,
name=data.name,
description=data.description,
sort_order=data.sort_order,
image_url=data.image_url,
)
)
return _node_row_to_category(node)
async def update_category(category: Category) -> Category:
row = await get_menu_node(category.id)
if not row:
raise ValueError("Category not found")
row.name = category.name
row.description = category.description
row.sort_order = category.sort_order
row.image_url = category.image_url
await update_menu_node(row)
return category
async def get_category(category_id: str) -> Optional[Category]:
row = await get_menu_node(category_id)
if not row or row.depth != 0:
return None
return _node_row_to_category(row)
async def get_categories(restaurant_id: str) -> list[Category]:
rows = await db.fetchall(
"""
SELECT * FROM restaurant.menu_nodes
WHERE restaurant_id = :rid AND depth = 0
ORDER BY sort_order, time
""",
{"rid": restaurant_id},
model=MenuNodeRow,
)
return [_node_row_to_category(r) for r in rows]
async def delete_category(category_id: str) -> None:
await delete_menu_node(category_id, cascade=True)
async def create_subcategory(data: CreateSubcategory) -> Subcategory:
parent = await get_menu_node(data.category_id)
if not parent:
raise ValueError("Category not found")
node = await create_menu_node(
CreateMenuNode(
restaurant_id=parent.restaurant_id,
parent_id=parent.id,
name=data.name,
sort_order=data.sort_order,
)
)
return _node_row_to_subcategory(node)
async def update_subcategory(subcategory: Subcategory) -> Subcategory:
row = await get_menu_node(subcategory.id)
if not row:
raise ValueError("Subcategory not found")
row.name = subcategory.name
row.sort_order = subcategory.sort_order
await update_menu_node(row)
return subcategory
async def get_subcategories(category_id: str) -> list[Subcategory]:
rows = await db.fetchall(
"""
SELECT * FROM restaurant.menu_nodes
WHERE parent_id = :pid
ORDER BY sort_order, time
""",
{"pid": category_id},
model=MenuNodeRow,
)
return [_node_row_to_subcategory(r) for r in rows]
async def delete_subcategory(subcategory_id: str) -> None:
await delete_menu_node(subcategory_id, cascade=True)
# --------------------------------------------------------------------- #
# Menu items #
# --------------------------------------------------------------------- #