FIX(winofy): add gooyal auth

add gooyal auth
This commit is contained in:
Haydar Ghasemi 2026-08-15 09:43:47 +03:30
parent 52adc732fa
commit d2cc4c2ec6
6 changed files with 108 additions and 15 deletions

View file

@ -1,12 +1,11 @@
SECRET_KEY=change-me
DEBUG=True
ALLOWED_HOSTS=localhost,127.0.0.1
ALLOWED_HOSTS=winofy-staging.winsoo.ir,localhost,127.0.0.1
DB_NAME=winofy_dev
DB_USER=
DB_PASSWORD=
DB_HOST=localhost
DB_PORT=5432
REDIS_URL=redis://localhost:6379/1
@ -26,3 +25,40 @@ OAUTH2_PROVIDER_SCOPES=
# macOS only — not needed on Linux where GDAL is on the system path
# GDAL_LIBRARY_PATH=/opt/homebrew/lib/libgdal.dylib
# GEOS_LIBRARY_PATH=/opt/homebrew/lib/libgeos_c.dylib
- API_BASE_PATH=api/
- SECRET_KEY=change-me
- ALLOWED_HOSTS=*
- CSRF_TRUSTED_ORIGINS=http://*,https://*,http://*.winsoo.ir,https://*.winsoo.ir
- TZ=Asia/Tehran
- DB_NAME=reservation_db
- DB_USER=root
- DB_HOST=reservation_db
- DB_PASSWORD=123456
- DEBUG=true
- BASE_OAUTH2_PROVIDER_PUBLIC_URL=https://accounts-staging.gooyal.ir/oauth2
- BASE_OAUTH2_PROVIDER_PRIVATE_URL=https://accounts-staging.gooyal.ir/oauth2
- CLIENT_ID=ULKUBOKeBGeP0hkTlzbfHhHXe4qfPZcg9H44qqh1
- CLIENT_SECRET=Cq8ZVkkQdP8IHOKxum4lkBVZOXE9OLmqWY1oseePOQh7KmCjYryWbgN5aeqwtXr6EzK8ttdbFm5Yt25ApZkb6ceze3TOPlObQ125UARin9A7DbjuDOHPar2tEafPWHlL
- SCOPES=wallet.wallet:get_balance wallet.application.deposit:verify wallet.application.deposit:submit wallet.application.withdraw:submit wallet.application.withdraw:verify walle>
- OAUTH2_PROVIDER_BASE_PUBLIC_URL=https://accounts-staging.gooyal.ir/oauth2
- OAUTH2_PROVIDER_BASE_PRIVATE_URL=https://accounts-staging.gooyal.ir/oauth2
- OAUTH2_PROVIDER_CLIENT_ID=ULKUBOKeBGeP0hkTlzbfHhHXe4qfPZcg9H44qqh1
- OAUTH2_PROVIDER_CLIENT_SECRET=Cq8ZVkkQdP8IHOKxum4lkBVZOXE9OLmqWY1oseePOQh7KmCjYryWbgN5aeqwtXr6EzK8ttdbFm5Yt25ApZkb6ceze3TOPlObQ125UARin9A7DbjuDOHPar2tEafPWHlL
- OAUTH2_PROVIDER_SCOPES=wallet.wallet:get_balance wallet.application.deposit:verify wallet.application.deposit:submit wallet.application.withdraw:submit wallet.application.withd>
- BASE_REDIS_URL=redis://redis:6379/3
- REDIS_BASE_URL=redis://redis:6379/3
- MINIO_ENDPOINT=drive.gooyal.ir
- MINIO_ACCESS_KEY=Irg3u493z63iJG3wJxah
- MINIO_SECRET_KEY=VctFgYVsvBSYd8gHanblS0QnRjot5tUFvtQLl3TX
- MINIO_USE_HTTPS=True
- MINIO_BUCKET_NAME=winsoo-reservation-media-files-bucket
- NOTIFICATIONS_EVENT_QUEUE=5527eced-a7c9-49d6-a59b-0bc40a81a1d6
- NOTIFICATIONS_OPERATOR_USER_UUID=7123eece-efda-4821-83a5-27dfa7bfd663
- NOTIFICATIONS_BASE_PUBLIC_URL=https://notifications-staging.gooyal.ir
- WALLET_BASE_PUBLIC_URL=https://wallet-staging.gooyal.ir
- WALLET_RIAL=af7d967f-30c0-409b-9066-2549f2da5e5e
- WALLET_RIAL_WALLET=af7d967f-30c0-409b-9066-2549f2da5e5e
- WALLET_REWARD=e7c9d4d1-4d1f-43b2-96f7-4d4a168f480d
- WALLET_REWARD_WALLET=e7c9d4d1-4d1f-43b2-96f7-4d4a168f480d
- LOKI_BASE_PUBLIC_URL=https://loki.winsoo.ir:443

View file

@ -4,6 +4,8 @@ from rest_framework.decorators import action
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from apps.gooyal_oauth2.rest_framework import IsAuthenticatedOrTokenMatchesOASRequirements
from apps.core.permissions import IsStoreOwner
from apps.stores.models import Store
@ -60,8 +62,13 @@ class SellerProductViewSet(viewsets.ModelViewSet):
"""Seller's own product management (S06 list, S07 add, S08 inventory)."""
schema_tags = ['Seller · Products']
permission_classes = [IsAuthenticated, IsStoreOwner]
serializer_class = SellerProductSerializer
# permission_classes = [IsAuthenticated, IsStoreOwner]
# TODO: IsStoreOwner?
permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements]
required_alternate_scopes = {
"POST": [[]],
}
def get_queryset(self):
if getattr(self, 'swagger_fake_view', False):

View file

@ -1,6 +1,8 @@
from rest_framework import mixins, viewsets
from rest_framework.permissions import AllowAny, IsAuthenticated
from apps.gooyal_oauth2.rest_framework import IsAuthenticatedOrTokenMatchesOASRequirements
from .models import Address, City, Neighborhood
from .serializers import AddressSerializer, CitySerializer, NeighborhoodSerializer
@ -28,8 +30,11 @@ class NeighborhoodViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, view
class AddressViewSet(viewsets.ModelViewSet):
schema_tags = ['Addresses']
permission_classes = [IsAuthenticated]
serializer_class = AddressSerializer
permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements]
required_alternate_scopes = {
"POST": [[]],
}
def get_queryset(self):
if getattr(self, 'swagger_fake_view', False):

View file

@ -6,6 +6,8 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from apps.gooyal_oauth2.rest_framework import IsAuthenticatedOrTokenMatchesOASRequirements
from apps.core.permissions import IsStoreOwner
from . import services
@ -27,8 +29,11 @@ class CartView(APIView):
"""The authenticated user's cart, grouped by store (C07)."""
schema_tags = ['Cart']
permission_classes = [IsAuthenticated]
serializer_class = CartSerializer
permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements]
required_alternate_scopes = {
"POST": [[]],
}
def get(self, request):
cart, _ = Cart.objects.get_or_create(user=request.user)
@ -45,8 +50,11 @@ class CartItemView(APIView):
"""Add/update/remove a single product line in the authenticated user's cart."""
schema_tags = ['Cart']
permission_classes = [IsAuthenticated]
serializer_class = CartItemWriteSerializer
permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements]
required_alternate_scopes = {
"POST": [[]],
}
@extend_schema(request=CartItemWriteSerializer, responses=CartItemSerializer)
def post(self, request):
@ -86,8 +94,11 @@ class CheckoutView(APIView):
"""Splits the authenticated customer's multi-store cart into per-store orders (C08)."""
schema_tags = ['Checkout']
permission_classes = [IsAuthenticated]
serializer_class = CheckoutSerializer
permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements]
required_alternate_scopes = {
"POST": [[]],
}
@extend_schema(request=CheckoutSerializer, responses=OrderGroupSerializer)
def post(self, request):
@ -102,8 +113,11 @@ class OrderGroupViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewse
"""Customer order history — each group may contain orders from several stores."""
schema_tags = ['Orders']
permission_classes = [IsAuthenticated]
serializer_class = OrderGroupSerializer
permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements]
required_alternate_scopes = {
"POST": [[]],
}
def get_queryset(self):
if getattr(self, 'swagger_fake_view', False):
@ -115,8 +129,11 @@ class OrderViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
"""Customer-facing single-order tracking (C09) + cancel."""
schema_tags = ['Orders']
permission_classes = [IsAuthenticated]
serializer_class = OrderSerializer
permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements]
required_alternate_scopes = {
"POST": [[]],
}
def get_queryset(self):
if getattr(self, 'swagger_fake_view', False):
@ -136,8 +153,13 @@ class SellerOrderViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, views
"""Seller order management (S09 list w/ status tabs, S10 detail + stepper actions)."""
schema_tags = ['Seller · Orders']
permission_classes = [IsAuthenticated, IsStoreOwner]
serializer_class = OrderSerializer
# permission_classes = [IsAuthenticated, IsStoreOwner]
# TODO: IsStoreOwner
permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements]
required_alternate_scopes = {
"POST": [[]],
}
def get_queryset(self):
if getattr(self, 'swagger_fake_view', False):
@ -184,8 +206,11 @@ class NotificationViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, view
"""Shared notification feed (S16 for sellers; same model serves the customer app)."""
schema_tags = ['Notifications']
permission_classes = [IsAuthenticated]
serializer_class = NotificationSerializer
permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements]
required_alternate_scopes = {
"POST": [[]],
}
def get_queryset(self):
if getattr(self, 'swagger_fake_view', False):

View file

@ -3,6 +3,7 @@ from rest_framework.decorators import action
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from apps.gooyal_oauth2.rest_framework import IsAuthenticatedOrTokenMatchesOASRequirements
from apps.core.permissions import IsStoreOwner
from .models import Review
@ -14,10 +15,14 @@ class ReviewViewSet(mixins.ListModelMixin, mixins.CreateModelMixin, viewsets.Gen
schema_tags = ['Reviews']
serializer_class = ReviewSerializer
permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements]
required_alternate_scopes = {
"POST": [[]],
}
def get_permissions(self):
if self.action == 'create':
return [IsAuthenticated()]
return [IsAuthenticatedOrTokenMatchesOASRequirements]
return [AllowAny()]
def get_queryset(self):
@ -32,8 +37,13 @@ class SellerReviewViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""Reviews left for the authenticated seller's store, with reply support."""
schema_tags = ['Seller · Reviews']
permission_classes = [IsAuthenticated, IsStoreOwner]
serializer_class = ReviewSerializer
# permission_classes = [IsAuthenticated, IsStoreOwner]
# TODO:
permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements]
required_alternate_scopes = {
"POST": [[]],
}
def get_queryset(self):
if getattr(self, 'swagger_fake_view', False):

View file

@ -9,6 +9,8 @@ from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from apps.gooyal_oauth2.rest_framework import IsAuthenticatedOrTokenMatchesOASRequirements
from apps.core.permissions import IsStoreOwner
from .models import Store, StoreCategory, StoreWorkingHours
@ -70,8 +72,11 @@ class SellerStoreView(APIView):
"""The authenticated seller's own store — GET/PATCH to manage it, POST to create it."""
schema_tags = ['Seller · Store']
permission_classes = [IsAuthenticated]
serializer_class = SellerStoreSerializer
permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements]
required_alternate_scopes = {
"POST": [[]],
}
def get(self, request):
store = get_object_or_404(Store, owner=request.user)
@ -102,8 +107,13 @@ class SellerStoreWorkingHoursView(APIView):
"""Bulk get/set the authenticated seller's weekly working hours (S14)."""
schema_tags = ['Seller · Store']
permission_classes = [IsAuthenticated, IsStoreOwner]
serializer_class = StoreWorkingHoursSerializer
# permission_classes = [IsAuthenticated, IsStoreOwner]
# TODO:
permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements]
required_alternate_scopes = {
"POST": [[]],
}
def get(self, request):
hours = StoreWorkingHours.objects.filter(store=request.user.store)