feat: add map image site module
This commit is contained in:
@@ -8,7 +8,7 @@ from app import serializers
|
||||
from app.auth import hash_password, require_admin
|
||||
from app.database import get_db
|
||||
from app.main import create_app
|
||||
from app.models import AdminUser, CtaBanner, Destination, DestinationAlias, HeroSlide, Lead, MediaAsset, Product, ProductImage, ThemeCard
|
||||
from app.models import AdminUser, CtaBanner, Destination, DestinationAlias, HeroSlide, Lead, MapImage, MediaAsset, Product, ProductImage, ThemeCard
|
||||
from app.routers import admin as admin_router
|
||||
from app.routers.admin import normalize_detail_sections, normalize_images
|
||||
from app.schemas import (
|
||||
@@ -179,6 +179,16 @@ def make_cta_banner(**overrides):
|
||||
)
|
||||
|
||||
|
||||
def make_map_image(**overrides):
|
||||
return MapImage(
|
||||
id=overrides.get("id", "map-test"),
|
||||
image=overrides.get("image", "https://cdn.example.test/map.webp"),
|
||||
isActive=overrides.get("isActive", True),
|
||||
createdAt=datetime(2026, 1, 1),
|
||||
updatedAt=datetime(2026, 1, 2),
|
||||
)
|
||||
|
||||
|
||||
def make_admin_user():
|
||||
return AdminUser(
|
||||
id="admin-test",
|
||||
@@ -442,7 +452,7 @@ def test_site_config_create_requires_module_primary_field():
|
||||
|
||||
def test_admin_site_config_hero_slides_use_dedicated_contract_without_targets():
|
||||
hero_slide = make_hero_slide(targetType="campaign", targetValue="campaign-test")
|
||||
fake_db = FakeDb(scalar_results=[[], [hero_slide], [], []])
|
||||
fake_db = FakeDb(scalar_results=[[], [hero_slide], [], [], []])
|
||||
app = authenticated_app(fake_db)
|
||||
|
||||
try:
|
||||
@@ -458,6 +468,32 @@ def test_admin_site_config_hero_slides_use_dedicated_contract_without_targets():
|
||||
assert "targetValue" not in hero
|
||||
|
||||
|
||||
def test_admin_site_config_includes_map_array_with_dedicated_contract():
|
||||
map_image = make_map_image()
|
||||
fake_db = FakeDb(scalar_results=[[], [], [map_image], [], []])
|
||||
app = authenticated_app(fake_db)
|
||||
|
||||
try:
|
||||
response = TestClient(app).get("/api/admin/site-config")
|
||||
finally:
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 200
|
||||
body = response.json()
|
||||
assert body["map"] == [
|
||||
{
|
||||
"id": "map-test",
|
||||
"image": "https://cdn.example.test/map.webp",
|
||||
"isActive": True,
|
||||
"createdAt": "2026-01-01T00:00:00",
|
||||
"updatedAt": "2026-01-02T00:00:00",
|
||||
}
|
||||
]
|
||||
assert "sortOrder" not in body["map"][0]
|
||||
assert "title" not in body["map"][0]
|
||||
assert "targetType" not in body["map"][0]
|
||||
|
||||
|
||||
def test_site_config_create_hero_slide_ignores_target_fields_and_returns_dedicated_contract():
|
||||
fake_db = FakeDb(scalar_values=[0])
|
||||
app = authenticated_app(fake_db)
|
||||
@@ -487,6 +523,47 @@ def test_site_config_create_hero_slide_ignores_target_fields_and_returns_dedicat
|
||||
assert created.targetValue is None
|
||||
|
||||
|
||||
def test_site_config_create_map_image_defaults_active_and_audits():
|
||||
fake_db = FakeDb(scalar_results=[[]])
|
||||
app = authenticated_app(fake_db)
|
||||
|
||||
try:
|
||||
response = TestClient(app).post(
|
||||
"/api/admin/site-config/map",
|
||||
json={"image": " https://cdn.example.test/guizhou-map.webp ", "title": "ignored", "sortOrder": 99},
|
||||
)
|
||||
finally:
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 201
|
||||
body = response.json()
|
||||
assert body["image"] == "https://cdn.example.test/guizhou-map.webp"
|
||||
assert body["isActive"] is True
|
||||
assert "title" not in body
|
||||
assert "sortOrder" not in body
|
||||
created = fake_db.added[0]
|
||||
assert isinstance(created, MapImage)
|
||||
assert created.image == "https://cdn.example.test/guizhou-map.webp"
|
||||
assert created.isActive is True
|
||||
assert fake_db.added[-1].entity == "map_image"
|
||||
assert fake_db.committed
|
||||
|
||||
|
||||
def test_site_config_create_map_image_rejects_duplicate_singleton():
|
||||
fake_db = FakeDb(scalar_results=[[make_map_image()]])
|
||||
app = authenticated_app(fake_db)
|
||||
|
||||
try:
|
||||
response = TestClient(app).post("/api/admin/site-config/map", json={"image": "https://cdn.example.test/new.webp"})
|
||||
finally:
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 409
|
||||
assert response.json()["code"] == "MAP_IMAGE_ALREADY_EXISTS"
|
||||
assert not fake_db.added
|
||||
assert not fake_db.committed
|
||||
|
||||
|
||||
def test_site_config_patch_hero_slide_ignores_target_fields_and_returns_dedicated_contract():
|
||||
hero_slide = make_hero_slide(targetType="campaign", targetValue="campaign-test")
|
||||
fake_db = FakeDb(get_result=hero_slide)
|
||||
@@ -515,6 +592,30 @@ def test_site_config_patch_hero_slide_ignores_target_fields_and_returns_dedicate
|
||||
assert hero_slide.targetValue == "campaign-test"
|
||||
|
||||
|
||||
def test_site_config_patch_map_image_updates_allowed_fields_only():
|
||||
map_image = make_map_image(isActive=True)
|
||||
fake_db = FakeDb(get_result=map_image)
|
||||
app = authenticated_app(fake_db)
|
||||
|
||||
try:
|
||||
response = TestClient(app).patch(
|
||||
"/api/admin/site-config/map/map-test",
|
||||
json={"image": " https://cdn.example.test/new-map.webp ", "isActive": False, "targetType": "ignored", "sortOrder": 1},
|
||||
)
|
||||
finally:
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 200
|
||||
body = response.json()
|
||||
assert body["image"] == "https://cdn.example.test/new-map.webp"
|
||||
assert body["isActive"] is False
|
||||
assert "targetType" not in body
|
||||
assert "sortOrder" not in body
|
||||
assert not hasattr(map_image, "targetType")
|
||||
assert fake_db.added[-1].action == "update"
|
||||
assert fake_db.added[-1].entity == "map_image"
|
||||
|
||||
|
||||
def test_site_config_patch_updates_destination_contract_fields():
|
||||
destination = make_destination()
|
||||
fake_db = FakeDb(get_result=destination)
|
||||
@@ -627,6 +728,38 @@ def test_site_config_reorder_rejects_duplicate_missing_and_unknown_ids(item_ids)
|
||||
assert not fake_db.committed
|
||||
|
||||
|
||||
def test_site_config_reorder_map_is_not_supported():
|
||||
fake_db = FakeDb()
|
||||
app = authenticated_app(fake_db)
|
||||
|
||||
try:
|
||||
response = TestClient(app).patch("/api/admin/site-config/map/reorder", json={"itemIds": ["map-test"]})
|
||||
finally:
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 400
|
||||
assert response.json()["code"] == "MODULE_CONFIG_REORDER_UNSUPPORTED"
|
||||
assert not fake_db.committed
|
||||
|
||||
|
||||
def test_site_config_delete_map_image_returns_json_and_audits_without_reorder():
|
||||
map_image = make_map_image()
|
||||
fake_db = FakeDb(get_result=map_image)
|
||||
app = authenticated_app(fake_db)
|
||||
|
||||
try:
|
||||
response = TestClient(app).delete("/api/admin/site-config/map/map-test")
|
||||
finally:
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"id": "map-test"}
|
||||
assert fake_db.deleted == [map_image]
|
||||
assert fake_db.added[-1].action == "delete"
|
||||
assert fake_db.added[-1].entity == "map_image"
|
||||
assert fake_db.committed
|
||||
|
||||
|
||||
def test_admin_media_upload_streams_image_to_oss_records_asset_and_audits(monkeypatch):
|
||||
uploaded = {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user