- New ad_control Django app: AdSurface + AdPlacement models with GLOBAL/LOCAL scope - Admin CRUD API at /api/v1/ad-control/ (JWT-protected): surfaces, placements, picker events - Placement lifecycle: DRAFT → ACTIVE|SCHEDULED → EXPIRED|DISABLED - LOCAL scope: Haversine ≤ 50km from event lat/lng (fixed radius, no config needed) - Consumer APIs: /api/events/featured-events/ and /api/events/top-events/ rewritten to use placement-based queries (same URL paths + response shape — no breaking changes) - Seed command: seed_surfaces --migrate converts existing is_featured/is_top_event booleans - mount: admin_api/urls.py → ad-control/, mobile_api/urls.py → replaced consumer views - settings.py: added ad_control to INSTALLED_APPS Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
25 lines
927 B
Python
25 lines
927 B
Python
from django.contrib import admin
|
|
from .models import AdSurface, AdPlacement
|
|
|
|
|
|
@admin.register(AdSurface)
|
|
class AdSurfaceAdmin(admin.ModelAdmin):
|
|
list_display = ('key', 'name', 'max_slots', 'layout_type', 'sort_behavior', 'is_active', 'active_count')
|
|
list_filter = ('is_active', 'layout_type')
|
|
search_fields = ('key', 'name')
|
|
readonly_fields = ('created_at',)
|
|
|
|
|
|
@admin.register(AdPlacement)
|
|
class AdPlacementAdmin(admin.ModelAdmin):
|
|
list_display = (
|
|
'id', 'event', 'surface', 'status', 'scope', 'priority',
|
|
'rank', 'boost_label', 'start_at', 'end_at', 'created_at',
|
|
)
|
|
list_filter = ('status', 'scope', 'priority', 'surface')
|
|
list_editable = ('status', 'scope', 'rank')
|
|
search_fields = ('event__name', 'event__title', 'boost_label')
|
|
raw_id_fields = ('event', 'created_by', 'updated_by')
|
|
readonly_fields = ('created_at', 'updated_at')
|
|
ordering = ('surface', 'rank')
|