let the Bazaar verify URL double as the OAuth redirect URI

The Bazaar account owner registered /api/payment/bazaar/verify as the
redirect URI. POST stays the app's purchase check; GET now takes Bazaar's
?code=, exchanges it for a refresh token and stores it in the new
BazaarCredential row, so connecting needs no SSH or .env edit.

The GET is unauthenticated, so it only acts inside a window opened from
the admin (or bazaar_authorize_link): 72 h by default, closed by the first
successful exchange, state checked when Bazaar echoes it. Authorize/token
URL shapes follow the known devapi v2 flow; not checked against Bazaar's
current docs, which did not load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-26 21:30:44 +03:30
parent 5d490edaf9
commit 8763ffd7bf
9 changed files with 414 additions and 9 deletions

View File

@@ -1,6 +1,8 @@
from django.contrib import admin
from django.contrib import admin, messages
from django.utils.html import format_html
from .models import Order, Transaction
from . import bazaar
from .models import BazaarCredential, Order, Transaction
class TransactionInline(admin.TabularInline):
@@ -19,3 +21,35 @@ class OrderAdmin(admin.ModelAdmin):
class TransactionAdmin(admin.ModelAdmin):
list_display = ('id', 'order', 'gateway', 'status', 'paid_at')
list_filter = ('gateway', 'status')
@admin.register(BazaarCredential)
class BazaarCredentialAdmin(admin.ModelAdmin):
"""
اتصالِ یک‌باره به API بازار، بدونِ SSH: action لینکِ «اجازه» را می‌سازد؛
صاحبِ حسابِ بازار بازش می‌کند و بازار به verify برمی‌گردد. خودِ توکن
هیچ‌جا نمایش داده نمی‌شود.
"""
list_display = ('__str__', 'authorized_at', 'pending_since')
fields = ('connected', 'authorized_at', 'pending_since')
readonly_fields = fields
actions = ['make_authorize_link']
@admin.display(boolean=True, description='توکن دارد')
def connected(self, obj):
return bool(obj.refresh_token)
def changelist_view(self, request, extra_context=None):
BazaarCredential.objects.get_or_create(pk=1)
return super().changelist_view(request, extra_context)
def has_add_permission(self, request):
return False
@admin.action(description='ساختِ لینکِ اتصال به بازار')
def make_authorize_link(self, request, queryset):
url = bazaar.start_authorization()
self.message_user(request, format_html(
'این لینک را صاحبِ حسابِ بازار باز کند و «اجازه» بزند: <a href="{0}">{0}</a>', url,
), messages.SUCCESS)