diff --git a/config/__pycache__/settings.cpython-311.pyc b/config/__pycache__/settings.cpython-311.pyc index 3f9c1b0..9ec34c7 100644 Binary files a/config/__pycache__/settings.cpython-311.pyc and b/config/__pycache__/settings.cpython-311.pyc differ diff --git a/config/__pycache__/urls.cpython-311.pyc b/config/__pycache__/urls.cpython-311.pyc index 96daead..3468c39 100644 Binary files a/config/__pycache__/urls.cpython-311.pyc and b/config/__pycache__/urls.cpython-311.pyc differ diff --git a/config/settings.py b/config/settings.py index 9b4df33..d858f0c 100644 --- a/config/settings.py +++ b/config/settings.py @@ -58,6 +58,7 @@ INSTALLED_APPS = [ 'django.contrib.staticfiles', 'rest_framework', 'rest_framework.authtoken', + 'drf_yasg', 'core', ] diff --git a/config/urls.py b/config/urls.py index 89a3eba..9e2e83c 100644 --- a/config/urls.py +++ b/config/urls.py @@ -4,8 +4,29 @@ from django.conf import settings from django.conf.urls.static import static from django.conf.urls.i18n import i18n_patterns +from rest_framework import permissions +from drf_yasg.views import get_schema_view +from drf_yasg import openapi + +schema_view = get_schema_view( + openapi.Info( + title="Masar Express API", + default_version='v1', + description="API documentation for Masar Express Mobile App & Drivers", + terms_of_service="https://www.google.com/policies/terms/", + contact=openapi.Contact(email="support@masarexpress.com"), + license=openapi.License(name="BSD License"), + ), + public=True, + permission_classes=(permissions.AllowAny,), +) + urlpatterns = [ path('i18n/', include('django.conf.urls.i18n')), + # Swagger / Redoc + path('swagger/', schema_view.without_ui(cache_timeout=0), name='schema-json'), + path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), + path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), ] urlpatterns += i18n_patterns( @@ -17,4 +38,4 @@ urlpatterns += i18n_patterns( if settings.DEBUG: urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) - urlpatterns += static("/assets/", document_root=settings.BASE_DIR / "assets") + urlpatterns += static("/assets/", document_root=settings.BASE_DIR / "assets") \ No newline at end of file diff --git a/core/__pycache__/api_views.cpython-311.pyc b/core/__pycache__/api_views.cpython-311.pyc index 34addef..b9df1fd 100644 Binary files a/core/__pycache__/api_views.cpython-311.pyc and b/core/__pycache__/api_views.cpython-311.pyc differ diff --git a/core/__pycache__/serializers.cpython-311.pyc b/core/__pycache__/serializers.cpython-311.pyc index 74c967f..c2e22d3 100644 Binary files a/core/__pycache__/serializers.cpython-311.pyc and b/core/__pycache__/serializers.cpython-311.pyc differ diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 7ed389c..0394ab0 100644 Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ diff --git a/core/api_views.py b/core/api_views.py index fd9febd..be583de 100644 --- a/core/api_views.py +++ b/core/api_views.py @@ -5,7 +5,7 @@ from rest_framework.authtoken.models import Token from rest_framework.views import APIView from django.db.models import Q from .models import Parcel, Profile -from .serializers import ParcelSerializer, ProfileSerializer +from .serializers import ParcelSerializer, ProfileSerializer, PublicParcelSerializer class CustomAuthToken(ObtainAuthToken): def post(self, request, *args, **kwargs): @@ -78,3 +78,13 @@ class UserProfileView(generics.RetrieveUpdateAPIView): def get_object(self): return self.request.user.profile + +class PublicParcelTrackView(generics.RetrieveAPIView): + """ + Public endpoint to track a parcel by its tracking number. + No authentication required. + """ + serializer_class = PublicParcelSerializer + permission_classes = [permissions.AllowAny] + queryset = Parcel.objects.all() + lookup_field = 'tracking_number' \ No newline at end of file diff --git a/core/serializers.py b/core/serializers.py index 90c468e..415be60 100644 --- a/core/serializers.py +++ b/core/serializers.py @@ -35,3 +35,24 @@ class ParcelSerializer(serializers.ModelSerializer): model = Parcel fields = '__all__' read_only_fields = ['shipper', 'tracking_number', 'created_at', 'updated_at', 'thawani_session_id'] + +class PublicParcelSerializer(serializers.ModelSerializer): + pickup_governate_name = serializers.CharField(source='pickup_governate.name', read_only=True) + pickup_city_name = serializers.CharField(source='pickup_city.name', read_only=True) + delivery_governate_name = serializers.CharField(source='delivery_governate.name', read_only=True) + delivery_city_name = serializers.CharField(source='delivery_city.name', read_only=True) + status_display = serializers.CharField(source='get_status_display', read_only=True) + + class Meta: + model = Parcel + fields = [ + 'tracking_number', + 'status', + 'status_display', + 'pickup_governate_name', + 'pickup_city_name', + 'delivery_governate_name', + 'delivery_city_name', + 'updated_at', + 'description' + ] \ No newline at end of file diff --git a/core/urls.py b/core/urls.py index 4c421ef..d6e84f3 100644 --- a/core/urls.py +++ b/core/urls.py @@ -70,5 +70,6 @@ urlpatterns = [ path('api/auth/token/', api_views.CustomAuthToken.as_view(), name='api_token_auth'), path('api/parcels/', api_views.ParcelListCreateView.as_view(), name='api_parcel_list'), path('api/parcels//', api_views.ParcelDetailView.as_view(), name='api_parcel_detail'), + path('api/track//', api_views.PublicParcelTrackView.as_view(), name='api_track_parcel'), path('api/profile/', api_views.UserProfileView.as_view(), name='api_user_profile'), -] +] \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 7ee7378..e59ab91 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,5 @@ Pillow weasyprint qrcode django-jazzmin==3.0.1 -djangorestframework==3.15.1 \ No newline at end of file +djangorestframework==3.15.1 +drf-yasg