feat: add map image site module

This commit is contained in:
duanshuwen
2026-07-02 08:57:49 +08:00
parent a47b4b5dd0
commit 7b329907f9
5 changed files with 221 additions and 8 deletions

View File

@@ -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 = {}