update
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
import sqlite3
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, HTTPException, status
|
||||
|
||||
from app.database import Database
|
||||
from app.schemas import AdSlot, AdSlotCreate, AdSlotUpdate
|
||||
from app.temple_scope import TempleId, ensure_temple_exists
|
||||
|
||||
|
||||
router = APIRouter(prefix="/ad-slots", tags=["ad-slots"])
|
||||
|
||||
AD_SLOT_COLUMNS = "id, temple_id, name, code, description, sort_order, is_active"
|
||||
|
||||
|
||||
def row_to_ad_slot(row: sqlite3.Row) -> AdSlot:
|
||||
return AdSlot(
|
||||
id=row["id"],
|
||||
temple_id=row["temple_id"],
|
||||
name=row["name"],
|
||||
code=row["code"],
|
||||
description=row["description"],
|
||||
sort_order=row["sort_order"],
|
||||
is_active=bool(row["is_active"]),
|
||||
)
|
||||
|
||||
|
||||
def raise_duplicate_code_error() -> None:
|
||||
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="广告位编码已存在")
|
||||
|
||||
|
||||
@router.get("", response_model=List[AdSlot])
|
||||
def list_ad_slots(db: Database, temple_id: TempleId) -> List[AdSlot]:
|
||||
ensure_temple_exists(db, temple_id)
|
||||
rows = db.execute(
|
||||
f"""
|
||||
SELECT {AD_SLOT_COLUMNS}
|
||||
FROM ad_slots
|
||||
WHERE temple_id = ?
|
||||
ORDER BY sort_order, id
|
||||
""",
|
||||
(temple_id,),
|
||||
).fetchall()
|
||||
return [row_to_ad_slot(row) for row in rows]
|
||||
|
||||
|
||||
@router.post("", response_model=AdSlot, status_code=status.HTTP_201_CREATED)
|
||||
def create_ad_slot(payload: AdSlotCreate, db: Database, temple_id: TempleId) -> AdSlot:
|
||||
ensure_temple_exists(db, temple_id)
|
||||
try:
|
||||
cursor = db.execute(
|
||||
"""
|
||||
INSERT INTO ad_slots
|
||||
(temple_id, name, code, description, title, image_url, sort_order, is_active)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
temple_id,
|
||||
payload.name,
|
||||
payload.code,
|
||||
payload.description,
|
||||
payload.name,
|
||||
"",
|
||||
payload.sort_order,
|
||||
int(payload.is_active),
|
||||
),
|
||||
)
|
||||
db.commit()
|
||||
except sqlite3.IntegrityError:
|
||||
raise_duplicate_code_error()
|
||||
|
||||
return get_ad_slot(cursor.lastrowid, db, temple_id)
|
||||
|
||||
|
||||
@router.get("/{ad_slot_id}", response_model=AdSlot)
|
||||
def get_ad_slot(ad_slot_id: int, db: Database, temple_id: TempleId) -> AdSlot:
|
||||
ensure_temple_exists(db, temple_id)
|
||||
row = db.execute(
|
||||
f"""
|
||||
SELECT {AD_SLOT_COLUMNS}
|
||||
FROM ad_slots
|
||||
WHERE id = ? AND temple_id = ?
|
||||
""",
|
||||
(ad_slot_id, temple_id),
|
||||
).fetchone()
|
||||
if row is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Ad slot not found")
|
||||
return row_to_ad_slot(row)
|
||||
|
||||
|
||||
@router.patch("/{ad_slot_id}", response_model=AdSlot)
|
||||
def update_ad_slot(ad_slot_id: int, payload: AdSlotUpdate, db: Database, temple_id: TempleId) -> AdSlot:
|
||||
ad_slot = get_ad_slot(ad_slot_id, db, temple_id)
|
||||
updates = payload.model_dump(exclude_unset=True)
|
||||
if not updates:
|
||||
return ad_slot
|
||||
|
||||
name = updates.get("name", ad_slot.name)
|
||||
try:
|
||||
db.execute(
|
||||
"""
|
||||
UPDATE ad_slots
|
||||
SET name = ?, code = ?, description = ?, title = ?, sort_order = ?, is_active = ?
|
||||
WHERE id = ? AND temple_id = ?
|
||||
""",
|
||||
(
|
||||
name,
|
||||
updates.get("code", ad_slot.code),
|
||||
updates.get("description", ad_slot.description),
|
||||
name,
|
||||
updates.get("sort_order", ad_slot.sort_order),
|
||||
int(updates.get("is_active", ad_slot.is_active)),
|
||||
ad_slot_id,
|
||||
temple_id,
|
||||
),
|
||||
)
|
||||
db.commit()
|
||||
except sqlite3.IntegrityError:
|
||||
raise_duplicate_code_error()
|
||||
|
||||
return get_ad_slot(ad_slot_id, db, temple_id)
|
||||
|
||||
|
||||
@router.delete("/{ad_slot_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
def delete_ad_slot(ad_slot_id: int, db: Database, temple_id: TempleId) -> None:
|
||||
ensure_temple_exists(db, temple_id)
|
||||
used = db.execute(
|
||||
"SELECT 1 FROM ads WHERE slot_id = ? AND temple_id = ? LIMIT 1",
|
||||
(ad_slot_id, temple_id),
|
||||
).fetchone()
|
||||
if used is not None:
|
||||
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="广告位已绑定广告,不能删除")
|
||||
|
||||
cursor = db.execute(
|
||||
"DELETE FROM ad_slots WHERE id = ? AND temple_id = ?",
|
||||
(ad_slot_id, temple_id),
|
||||
)
|
||||
db.commit()
|
||||
if cursor.rowcount == 0:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Ad slot not found")
|
||||
@@ -0,0 +1,182 @@
|
||||
import sqlite3
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, HTTPException, status
|
||||
|
||||
from app.database import Database
|
||||
from app.schemas import Ad, AdCreate, AdUpdate
|
||||
from app.temple_scope import TempleId, ensure_temple_exists
|
||||
|
||||
|
||||
router = APIRouter(prefix="/ads", tags=["ads"])
|
||||
|
||||
AD_COLUMNS = """
|
||||
ads.id, ads.temple_id, ads.slot_id, ad_slots.name AS slot_name, ad_slots.code AS slot_code,
|
||||
ads.title, ads.image_url, ads.target_type, ads.target_url, ads.product_id,
|
||||
products.name AS product_name, ads.sort_order, ads.is_active
|
||||
"""
|
||||
|
||||
|
||||
def row_to_ad(row: sqlite3.Row) -> Ad:
|
||||
return Ad(
|
||||
id=row["id"],
|
||||
temple_id=row["temple_id"],
|
||||
slot_id=row["slot_id"],
|
||||
slot_name=row["slot_name"],
|
||||
slot_code=row["slot_code"],
|
||||
title=row["title"],
|
||||
image_url=row["image_url"],
|
||||
target_type=row["target_type"],
|
||||
target_url=row["target_url"],
|
||||
product_id=row["product_id"],
|
||||
product_name=row["product_name"],
|
||||
sort_order=row["sort_order"],
|
||||
is_active=bool(row["is_active"]),
|
||||
)
|
||||
|
||||
|
||||
def ensure_slot_in_temple(db: Database, slot_id: int, temple_id: int) -> None:
|
||||
row = db.execute(
|
||||
"SELECT id FROM ad_slots WHERE id = ? AND temple_id = ?",
|
||||
(slot_id, temple_id),
|
||||
).fetchone()
|
||||
if row is None:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="请选择当前寺院下的广告位")
|
||||
|
||||
|
||||
def ensure_product_in_temple(db: Database, product_id: int | None, temple_id: int) -> None:
|
||||
if product_id is None:
|
||||
return
|
||||
row = db.execute(
|
||||
"SELECT id FROM products WHERE id = ? AND temple_id = ?",
|
||||
(product_id, temple_id),
|
||||
).fetchone()
|
||||
if row is None:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="请选择当前寺院下的商品")
|
||||
|
||||
|
||||
def normalize_ad_payload(
|
||||
payload: AdCreate | AdUpdate,
|
||||
temple_id: int,
|
||||
db: Database,
|
||||
fallback: Ad | None = None,
|
||||
) -> tuple[int, str, str, str, str | None, int | None, int, int]:
|
||||
data = payload.model_dump(exclude_unset=fallback is not None)
|
||||
|
||||
def get_value(name: str, default):
|
||||
if name in data:
|
||||
return data[name]
|
||||
if fallback is not None:
|
||||
return getattr(fallback, name)
|
||||
return default
|
||||
|
||||
slot_id = get_value("slot_id", None)
|
||||
if slot_id is None:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="请选择广告位")
|
||||
ensure_slot_in_temple(db, slot_id, temple_id)
|
||||
|
||||
target_type = get_value("target_type", "link")
|
||||
target_url = get_value("target_url", None)
|
||||
product_id = get_value("product_id", None)
|
||||
|
||||
if target_type == "link":
|
||||
product_id = None
|
||||
if not target_url:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="链接类型需要填写跳转地址")
|
||||
else:
|
||||
target_url = None
|
||||
ensure_product_in_temple(db, product_id, temple_id)
|
||||
if product_id is None:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="应用类型需要选择商品")
|
||||
|
||||
return (
|
||||
slot_id,
|
||||
get_value("title", ""),
|
||||
get_value("image_url", ""),
|
||||
target_type,
|
||||
target_url,
|
||||
product_id,
|
||||
get_value("sort_order", 0),
|
||||
int(get_value("is_active", True)),
|
||||
)
|
||||
|
||||
|
||||
@router.get("", response_model=List[Ad])
|
||||
def list_ads(db: Database, temple_id: TempleId) -> List[Ad]:
|
||||
ensure_temple_exists(db, temple_id)
|
||||
rows = db.execute(
|
||||
f"""
|
||||
SELECT {AD_COLUMNS}
|
||||
FROM ads
|
||||
JOIN ad_slots ON ad_slots.id = ads.slot_id
|
||||
LEFT JOIN products ON products.id = ads.product_id
|
||||
WHERE ads.temple_id = ?
|
||||
ORDER BY ad_slots.sort_order, ads.sort_order, ads.id
|
||||
""",
|
||||
(temple_id,),
|
||||
).fetchall()
|
||||
return [row_to_ad(row) for row in rows]
|
||||
|
||||
|
||||
@router.post("", response_model=Ad, status_code=status.HTTP_201_CREATED)
|
||||
def create_ad(payload: AdCreate, db: Database, temple_id: TempleId) -> Ad:
|
||||
ensure_temple_exists(db, temple_id)
|
||||
cursor = db.execute(
|
||||
"""
|
||||
INSERT INTO ads
|
||||
(temple_id, slot_id, title, image_url, target_type, target_url, product_id, sort_order, is_active)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(temple_id, *normalize_ad_payload(payload, temple_id, db)),
|
||||
)
|
||||
db.commit()
|
||||
return get_ad(cursor.lastrowid, db, temple_id)
|
||||
|
||||
|
||||
@router.get("/{ad_id}", response_model=Ad)
|
||||
def get_ad(ad_id: int, db: Database, temple_id: TempleId) -> Ad:
|
||||
ensure_temple_exists(db, temple_id)
|
||||
row = db.execute(
|
||||
f"""
|
||||
SELECT {AD_COLUMNS}
|
||||
FROM ads
|
||||
JOIN ad_slots ON ad_slots.id = ads.slot_id
|
||||
LEFT JOIN products ON products.id = ads.product_id
|
||||
WHERE ads.id = ? AND ads.temple_id = ?
|
||||
""",
|
||||
(ad_id, temple_id),
|
||||
).fetchone()
|
||||
if row is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Ad not found")
|
||||
return row_to_ad(row)
|
||||
|
||||
|
||||
@router.patch("/{ad_id}", response_model=Ad)
|
||||
def update_ad(ad_id: int, payload: AdUpdate, db: Database, temple_id: TempleId) -> Ad:
|
||||
ad = get_ad(ad_id, db, temple_id)
|
||||
if not payload.model_dump(exclude_unset=True):
|
||||
return ad
|
||||
|
||||
db.execute(
|
||||
"""
|
||||
UPDATE ads
|
||||
SET slot_id = ?, title = ?, image_url = ?, target_type = ?, target_url = ?,
|
||||
product_id = ?, sort_order = ?, is_active = ?
|
||||
WHERE id = ? AND temple_id = ?
|
||||
""",
|
||||
(*normalize_ad_payload(payload, temple_id, db, ad), ad_id, temple_id),
|
||||
)
|
||||
db.commit()
|
||||
return get_ad(ad_id, db, temple_id)
|
||||
|
||||
|
||||
@router.delete("/{ad_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
def delete_ad(ad_id: int, db: Database, temple_id: TempleId) -> None:
|
||||
ensure_temple_exists(db, temple_id)
|
||||
cursor = db.execute(
|
||||
"DELETE FROM ads WHERE id = ? AND temple_id = ?",
|
||||
(ad_id, temple_id),
|
||||
)
|
||||
db.commit()
|
||||
if cursor.rowcount == 0:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Ad not found")
|
||||
@@ -0,0 +1,238 @@
|
||||
import sqlite3
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, HTTPException, status
|
||||
|
||||
from app.database import Database
|
||||
from app.schemas import FeatureIcon, FeatureIconCopyRequest, FeatureIconCreate, FeatureIconUpdate
|
||||
from app.temple_scope import TempleId, ensure_temple_exists
|
||||
|
||||
|
||||
router = APIRouter(prefix="/feature-icons", tags=["feature-icons"])
|
||||
|
||||
ICON_COLUMNS = """
|
||||
feature_icons.id, feature_icons.temple_id, feature_icons.title, feature_icons.icon_url,
|
||||
feature_icons.target_type, feature_icons.target_url, feature_icons.product_id,
|
||||
products.name AS product_name, feature_icons.sort_order, feature_icons.is_active
|
||||
"""
|
||||
|
||||
|
||||
def row_to_icon(row: sqlite3.Row) -> FeatureIcon:
|
||||
return FeatureIcon(
|
||||
id=row["id"],
|
||||
temple_id=row["temple_id"],
|
||||
title=row["title"],
|
||||
icon_url=row["icon_url"],
|
||||
target_type=row["target_type"],
|
||||
target_url=row["target_url"],
|
||||
product_id=row["product_id"],
|
||||
product_name=row["product_name"],
|
||||
sort_order=row["sort_order"],
|
||||
is_active=bool(row["is_active"]),
|
||||
)
|
||||
|
||||
|
||||
def ensure_product_in_temple(db: Database, product_id: int | None, temple_id: int) -> None:
|
||||
if product_id is None:
|
||||
return
|
||||
row = db.execute(
|
||||
"SELECT id FROM products WHERE id = ? AND temple_id = ?",
|
||||
(product_id, temple_id),
|
||||
).fetchone()
|
||||
if row is None:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="请选择当前寺院下的商品")
|
||||
|
||||
|
||||
def normalize_icon_payload(
|
||||
payload: FeatureIconCreate | FeatureIconUpdate,
|
||||
temple_id: int,
|
||||
db: Database,
|
||||
fallback: FeatureIcon | None = None,
|
||||
) -> tuple[str, str, str, str | None, int | None, int, int]:
|
||||
data = payload.model_dump(exclude_unset=fallback is not None)
|
||||
|
||||
def get_value(name: str, default):
|
||||
if name in data:
|
||||
return data[name]
|
||||
if fallback is not None:
|
||||
return getattr(fallback, name)
|
||||
return default
|
||||
|
||||
target_type = get_value("target_type", "link")
|
||||
target_url = get_value("target_url", None)
|
||||
product_id = get_value("product_id", None)
|
||||
|
||||
if target_type == "link":
|
||||
product_id = None
|
||||
if not target_url:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="链接类型需要填写跳转地址")
|
||||
else:
|
||||
target_url = None
|
||||
ensure_product_in_temple(db, product_id, temple_id)
|
||||
if product_id is None:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="应用类型需要选择商品")
|
||||
|
||||
return (
|
||||
get_value("title", ""),
|
||||
get_value("icon_url", ""),
|
||||
target_type,
|
||||
target_url,
|
||||
product_id,
|
||||
get_value("sort_order", 0),
|
||||
int(get_value("is_active", True)),
|
||||
)
|
||||
|
||||
|
||||
@router.get("", response_model=List[FeatureIcon])
|
||||
def list_icons(db: Database, temple_id: TempleId) -> List[FeatureIcon]:
|
||||
ensure_temple_exists(db, temple_id)
|
||||
rows = db.execute(
|
||||
f"""
|
||||
SELECT {ICON_COLUMNS}
|
||||
FROM feature_icons
|
||||
LEFT JOIN products ON products.id = feature_icons.product_id
|
||||
WHERE feature_icons.temple_id = ?
|
||||
ORDER BY feature_icons.sort_order, feature_icons.id
|
||||
""",
|
||||
(temple_id,),
|
||||
).fetchall()
|
||||
return [row_to_icon(row) for row in rows]
|
||||
|
||||
|
||||
@router.get("/source/{source_temple_id}", response_model=List[FeatureIcon])
|
||||
def list_source_icons(source_temple_id: int, db: Database) -> List[FeatureIcon]:
|
||||
ensure_temple_exists(db, source_temple_id)
|
||||
rows = db.execute(
|
||||
f"""
|
||||
SELECT {ICON_COLUMNS}
|
||||
FROM feature_icons
|
||||
LEFT JOIN products ON products.id = feature_icons.product_id
|
||||
WHERE feature_icons.temple_id = ?
|
||||
ORDER BY feature_icons.sort_order, feature_icons.id
|
||||
""",
|
||||
(source_temple_id,),
|
||||
).fetchall()
|
||||
return [row_to_icon(row) for row in rows]
|
||||
|
||||
|
||||
@router.post("", response_model=FeatureIcon, status_code=status.HTTP_201_CREATED)
|
||||
def create_icon(payload: FeatureIconCreate, db: Database, temple_id: TempleId) -> FeatureIcon:
|
||||
ensure_temple_exists(db, temple_id)
|
||||
cursor = db.execute(
|
||||
"""
|
||||
INSERT INTO feature_icons
|
||||
(temple_id, title, icon_url, target_type, target_url, product_id, sort_order, is_active)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(temple_id, *normalize_icon_payload(payload, temple_id, db)),
|
||||
)
|
||||
db.commit()
|
||||
return get_icon(cursor.lastrowid, db, temple_id)
|
||||
|
||||
|
||||
@router.post("/copy", response_model=List[FeatureIcon], status_code=status.HTTP_201_CREATED)
|
||||
def copy_icons(payload: FeatureIconCopyRequest, db: Database, temple_id: TempleId) -> List[FeatureIcon]:
|
||||
ensure_temple_exists(db, temple_id)
|
||||
ensure_temple_exists(db, payload.source_temple_id)
|
||||
if payload.source_temple_id == temple_id:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="请选择其他寺院的图标")
|
||||
|
||||
placeholders = ",".join("?" for _ in payload.icon_ids)
|
||||
rows = db.execute(
|
||||
f"""
|
||||
SELECT id, title, icon_url, target_type, target_url, product_id, sort_order, is_active
|
||||
FROM feature_icons
|
||||
WHERE temple_id = ? AND id IN ({placeholders})
|
||||
ORDER BY sort_order, id
|
||||
""",
|
||||
(payload.source_temple_id, *payload.icon_ids),
|
||||
).fetchall()
|
||||
if not rows:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="未找到可复制的图标")
|
||||
|
||||
new_ids: list[int] = []
|
||||
for row in rows:
|
||||
product_id = row["product_id"]
|
||||
is_active = row["is_active"]
|
||||
if row["target_type"] == "app":
|
||||
product_id = None
|
||||
is_active = 0
|
||||
cursor = db.execute(
|
||||
"""
|
||||
INSERT INTO feature_icons
|
||||
(temple_id, title, icon_url, target_type, target_url, product_id, sort_order, is_active)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
temple_id,
|
||||
row["title"],
|
||||
row["icon_url"],
|
||||
row["target_type"],
|
||||
row["target_url"],
|
||||
product_id,
|
||||
row["sort_order"],
|
||||
is_active,
|
||||
),
|
||||
)
|
||||
new_ids.append(cursor.lastrowid)
|
||||
|
||||
db.commit()
|
||||
placeholders = ",".join("?" for _ in new_ids)
|
||||
copied_rows = db.execute(
|
||||
f"""
|
||||
SELECT {ICON_COLUMNS}
|
||||
FROM feature_icons
|
||||
LEFT JOIN products ON products.id = feature_icons.product_id
|
||||
WHERE feature_icons.temple_id = ? AND feature_icons.id IN ({placeholders})
|
||||
ORDER BY feature_icons.sort_order, feature_icons.id
|
||||
""",
|
||||
(temple_id, *new_ids),
|
||||
).fetchall()
|
||||
return [row_to_icon(row) for row in copied_rows]
|
||||
|
||||
|
||||
@router.get("/{icon_id}", response_model=FeatureIcon)
|
||||
def get_icon(icon_id: int, db: Database, temple_id: TempleId) -> FeatureIcon:
|
||||
ensure_temple_exists(db, temple_id)
|
||||
row = db.execute(
|
||||
f"""
|
||||
SELECT {ICON_COLUMNS}
|
||||
FROM feature_icons
|
||||
LEFT JOIN products ON products.id = feature_icons.product_id
|
||||
WHERE feature_icons.id = ? AND feature_icons.temple_id = ?
|
||||
""",
|
||||
(icon_id, temple_id),
|
||||
).fetchone()
|
||||
if row is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Icon not found")
|
||||
return row_to_icon(row)
|
||||
|
||||
|
||||
@router.patch("/{icon_id}", response_model=FeatureIcon)
|
||||
def update_icon(icon_id: int, payload: FeatureIconUpdate, db: Database, temple_id: TempleId) -> FeatureIcon:
|
||||
icon = get_icon(icon_id, db, temple_id)
|
||||
if not payload.model_dump(exclude_unset=True):
|
||||
return icon
|
||||
|
||||
db.execute(
|
||||
"""
|
||||
UPDATE feature_icons
|
||||
SET title = ?, icon_url = ?, target_type = ?, target_url = ?, product_id = ?, sort_order = ?, is_active = ?
|
||||
WHERE id = ? AND temple_id = ?
|
||||
""",
|
||||
(*normalize_icon_payload(payload, temple_id, db, icon), icon_id, temple_id),
|
||||
)
|
||||
db.commit()
|
||||
return get_icon(icon_id, db, temple_id)
|
||||
|
||||
|
||||
@router.delete("/{icon_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
def delete_icon(icon_id: int, db: Database, temple_id: TempleId) -> None:
|
||||
ensure_temple_exists(db, temple_id)
|
||||
cursor = db.execute(
|
||||
"DELETE FROM feature_icons WHERE id = ? AND temple_id = ?",
|
||||
(icon_id, temple_id),
|
||||
)
|
||||
db.commit()
|
||||
if cursor.rowcount == 0:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Icon not found")
|
||||
Reference in New Issue
Block a user