FIX(promotions): include filters.py/docs/urls.py in admin panel restructure
These were dropped from the prior restructuring commit by a failed multi-pathspec git add (one invalid path aborted the whole call). Wires up filters.py's Admin*Filter classes, mounts apps.promotions.urls (the new router package) instead of the deleted urls_admin module, and brings docs/adminpanel_technical.md in sync with the new layout. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
1d77303f00
commit
c359105019
3 changed files with 58 additions and 15 deletions
|
|
@ -1,11 +1,36 @@
|
|||
import django_filters
|
||||
|
||||
from .models import Sample
|
||||
from .handlers import ProcessorTypeChoices
|
||||
from .models import Promotion, PaymentStateChoices
|
||||
|
||||
|
||||
class SampleFilter(django_filters.FilterSet):
|
||||
class AdminPromotionFilter(django_filters.FilterSet):
|
||||
user_uuid = django_filters.UUIDFilter(field_name='user_uuid')
|
||||
plan = django_filters.UUIDFilter(field_name='plan__uuid')
|
||||
promotion_type = django_filters.ChoiceFilter(field_name='plan__processor', choices=ProcessorTypeChoices.choices)
|
||||
state = django_filters.ChoiceFilter(field_name='state', choices=PaymentStateChoices.choices)
|
||||
event_label = django_filters.CharFilter(field_name='event__label', lookup_expr='exact')
|
||||
created_after = django_filters.DateTimeFilter(field_name='created_at', lookup_expr='gte')
|
||||
created_before = django_filters.DateTimeFilter(field_name='created_at', lookup_expr='lte')
|
||||
|
||||
class Meta:
|
||||
model = Sample
|
||||
fields = {
|
||||
'data': ['exact'],
|
||||
}
|
||||
model = Promotion
|
||||
fields = ['user_uuid', 'plan', 'promotion_type', 'state', 'event_label', 'created_after', 'created_before']
|
||||
|
||||
|
||||
class AdminReferralFilter(django_filters.FilterSet):
|
||||
# invited_by == Promotion.user_uuid: in the referral recipient DSL
|
||||
# ("->event:referral") this is who gets paid, i.e. the referrer.
|
||||
invited_by = django_filters.UUIDFilter(field_name='user_uuid')
|
||||
# invited_user lives only in free-form JSON (event.data['user']), so this is a
|
||||
# CharFilter, not UUIDFilter: JSONField key-transform lookups compare against
|
||||
# the stored string, not a native UUID the adapter can serialize.
|
||||
invited_user = django_filters.CharFilter(field_name='event__data__user')
|
||||
plan = django_filters.UUIDFilter(field_name='plan__uuid')
|
||||
state = django_filters.ChoiceFilter(field_name='state', choices=PaymentStateChoices.choices)
|
||||
created_after = django_filters.DateTimeFilter(field_name='created_at', lookup_expr='gte')
|
||||
created_before = django_filters.DateTimeFilter(field_name='created_at', lookup_expr='lte')
|
||||
|
||||
class Meta:
|
||||
model = Promotion
|
||||
fields = ['invited_user', 'invited_by', 'plan', 'state', 'created_after', 'created_before']
|
||||
|
|
|
|||
|
|
@ -1,21 +1,38 @@
|
|||
# Admin panel — technical reference
|
||||
|
||||
Two read-only endpoints added for the admin panel: **Promotions** (every promotion received, per user) and **Referral System** (referral activity). Both live in `apps/promotions`, following this repo's existing `_user` / `_application` file-suffix convention with a new `_admin` suffix:
|
||||
Two read-only endpoints added for the admin panel: **Promotions** (every promotion received, per user) and **Referral System** (referral activity). They live under `apps/promotions`, structured to match the admin/users folder split used by the sibling `advertising` service (`apps/crm`, `apps/escrow`, `apps/stores` there each split `views/`, `serializers/`, and `urls/` into `admin/`/`users/` subpackages, sharing one `DefaultRouter`). Applied here for the admin slice only — the pre-existing `views_user.py` / `views_application.py` / `urls_user.py` / `urls_application.py` (user-token and application-token APIs) were intentionally left untouched, since restructuring those would rename URL namespaces already relied on by `tests.py` and any external caller.
|
||||
|
||||
| File | Purpose |
|
||||
| Path | Purpose |
|
||||
|---|---|
|
||||
| `apps/promotions/views_admin.py` | `AdminPromotionListApiView`, `AdminPromotionDetailApiView`, `AdminReferralListApiView`, `AdminReferralDetailApiView` |
|
||||
| `apps/promotions/urls_admin.py` | URL routes, `app_name = 'promotions-admin'` |
|
||||
| `apps/promotions/filters_admin.py` | `AdminPromotionFilter`, `AdminReferralFilter` (django-filter `FilterSet`s) |
|
||||
| `apps/promotions/serializers.py` | `AdminPromotionSerializer`, `AdminReferralSerializer`, `AdminPlanSummarySerializer` (added alongside the existing serializers, this repo does not split serializers by audience) |
|
||||
| `apps/promotions/views/admin/promotion.py` | `AdminPromotionViewSet` |
|
||||
| `apps/promotions/views/admin/referral.py` | `AdminReferralViewSet` |
|
||||
| `apps/promotions/views/admin/__init__.py`, `apps/promotions/views/__init__.py` | re-export the two viewsets |
|
||||
| `apps/promotions/urls/router.py` | shared `DefaultRouter` for the admin API |
|
||||
| `apps/promotions/urls/admin_urls.py` | registers both viewsets on the router |
|
||||
| `apps/promotions/urls/__init__.py` | combines `router.urls`, sets `app_name = 'promotions-admin'` |
|
||||
| `apps/promotions/serializers/admin/promotion.py` | `AdminPlanSummarySerializer`, `AdminPromotionSerializer` |
|
||||
| `apps/promotions/serializers/admin/referral.py` | `AdminReferralSerializer` |
|
||||
| `apps/promotions/serializers/admin/__init__.py`, `apps/promotions/serializers/__init__.py` | re-export, alongside the pre-existing (now `serializers/common.py`) serializers |
|
||||
| `apps/promotions/filters.py` | `AdminPromotionFilter`, `AdminReferralFilter` — stays a single flat file, matching how `advertising`'s `filters.py` (e.g. `apps/crm/filters.py`) is *not* split into subfolders even though views/serializers/urls are |
|
||||
|
||||
Mounted in `main/urls.py`:
|
||||
|
||||
```python
|
||||
path('api/v2/promotions/admin/', include('apps.promotions.urls_admin', namespace='promotions-admin')),
|
||||
path('api/v2/promotions/admin/', include('apps.promotions.urls', namespace='promotions-admin')),
|
||||
```
|
||||
|
||||
No models or migrations were changed. Both endpoints are pure `ListAPIView`/`RetrieveAPIView` reads over the existing `Promotion` table.
|
||||
No models or migrations were changed. Both resources are `GenericViewSet` + `ListModelMixin`/`RetrieveModelMixin` (matching `AdminTicketViewSet` in `advertising`'s `apps/crm/views/admin/ticket.py`) registered on one router, not separate `ListAPIView`/`RetrieveAPIView` classes.
|
||||
|
||||
### URL names
|
||||
|
||||
Router-generated, under the `promotions-admin` namespace:
|
||||
|
||||
| Name | Path |
|
||||
|---|---|
|
||||
| `promotions-admin:admin-promotions-list` | `GET /api/v2/promotions/admin/promotions/` |
|
||||
| `promotions-admin:admin-promotions-detail` | `GET /api/v2/promotions/admin/promotions/<uuid>/` |
|
||||
| `promotions-admin:admin-referrals-list` | `GET /api/v2/promotions/admin/referrals/` |
|
||||
| `promotions-admin:admin-referrals-detail` | `GET /api/v2/promotions/admin/referrals/<uuid>/` |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -207,3 +224,4 @@ GET /api/v2/promotions/admin/referrals/?invited_by=1bb3b561-2823-4a3e-be12-edc5a
|
|||
- **Detail routes are of limited independent use.** `AdminPromotionDetailApiView` / `AdminReferralDetailApiView` return the same shape as one row of the list endpoint; included for REST completeness (e.g. deep-linking from a table row in the admin UI) but the list endpoint with `plan`/`state` filters covers most real usage.
|
||||
- **New scopes (`admin.promotions:retrieve`, `admin.referrals:retrieve`) need to be registered on the central accounts OAuth2 provider** before any real token can carry them — that's outside this checkout.
|
||||
- **No automated tests were added** for these two endpoints (matching the request's scope: verified via `manage.py check`, URL resolution, and an `APIRequestFactory` smoke test against an in-memory SQLite DB with the app's Postgres/JSONField-`GinIndex` usage stubbed around, run manually — see `apps/promotions/tests.py` for the existing `APITestCase` pattern if formal tests are wanted later).
|
||||
- **The admin/users folder split was applied to the admin slice only.** `views_user.py`, `views_application.py`, `urls_user.py`, `urls_application.py`, and the non-admin serializers (now `serializers/common.py`) were left in place rather than also converted to `views/users/`, `views/application/`, etc., because that would rename the `promotions` / `promotions-application` URL namespaces already used by `tests.py`'s `reverse()` calls (and possibly external callers) — a breaking change outside what was asked for here.
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ urlpatterns = [
|
|||
path('oauth2/', include('oauth2_provider.urls', namespace='oauth2_provider')),
|
||||
path('promotions/', include('apps.promotions.urls_user', namespace='promotions')),
|
||||
path('api/v2/promotions/application/<user_uuid>/', include('apps.promotions.urls_application', namespace='promotions-application')),
|
||||
path('api/v2/promotions/admin/', include('apps.promotions.urls_admin', namespace='promotions-admin')),
|
||||
path('api/v2/promotions/admin/', include('apps.promotions.urls', namespace='promotions-admin')),
|
||||
]
|
||||
|
||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue