basic healthcheck and status

This commit is contained in:
Sayyid Hamid Mahdavi 2026-03-15 15:08:32 +03:30
parent 03ca49fbe3
commit 8f7f56f3df
4 changed files with 88 additions and 5 deletions

View file

@ -1,10 +1,48 @@
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView
from oauth2_provider.contrib.rest_framework import IsAuthenticatedOrTokenHasScope
from rest_framework import generics
from rest_framework.exceptions import APIException, ErrorDetail
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.views import APIView
from utils.exceptions import StatusError
# Create your views here.
@method_decorator(login_required, name='dispatch')
class HomeView(TemplateView):
template_name = 'core/home.html'
class StatusView(APIView):
permission_classes = [AllowAny]
def get(self, request, format=None):
if self.request.GET.get('raise_error'):
raise StatusError(
# code='service_unavailable_at_now',
detail={
# "code": 'service_unavailable_at_now',
"timestamp": timezone.now().isoformat(),
"message": "برخی سرویس‌های خارجی در دسترس نیستند لطفا بعدا تلاش کنید"
},
)
data = {
"status": "ok",
}
return Response(data)
class HealthcheckView(APIView):
permission_classes = [AllowAny]
def get(self, request, format=None):
data = {
"is_healthy": True
}
return Response(data)

View file

@ -30,6 +30,12 @@ class GatewayChoise(TextChoices):
SEP = 'sep', _('sep')
class GatewayPolicy(BasePGModel):
application = models.ForeignKey(oauth2_settings.APPLICATION_MODEL, on_delete=models.PROTECT,
related_name='+', null=True, blank=True, unique=True)
preference_gateway = models.JSONField(default=list, blank=True)
# TODO: use generic relation
class PaymentRequest(models.Model):
id = None

View file

@ -1,6 +1,7 @@
from django.urls import path, include
from .views import PaymentRequestView, PaymentRequestCreateApiView, PaymentConfirmView, \
ApplicationPaymentRequestCreateApiView, CalculateCommissionView
from ..core.views import HealthcheckView, StatusView
app_name = "pg"
@ -10,4 +11,8 @@ urlpatterns = [
path('api/charge_create/', PaymentRequestCreateApiView.as_view(), name='charge-request-create-api-view'),
path('api/application/charge_create/<uuid>', ApplicationPaymentRequestCreateApiView.as_view(), name='application-user-charge-request-create-api-view'),
path('api/calculate_commission/', CalculateCommissionView.as_view(), name='calculate-commission-view'),
path('api/healthcheck', HealthcheckView.as_view(), name='healthcheck-view'),
path('api/status', StatusView.as_view(), name='status-view'),
]

View file

@ -10,16 +10,34 @@ def exception_handler(exc, context):
response = drf_exception_handler(exc, context)
if response is not None:
# ساختار دلخواه خود را تعریف می‌کنیم
try:
if isinstance(exc.detail, dict):
if 'code' in exc.detail:
error_code = exc.detail['code']
else:
attr = next(iter(exc.detail))
error_code = exc.detail[attr].code
else:
error_code = exc.detail.code or exc.code
except:
error_code = ''
response_data = {
'success': False,
'status_code': response.status_code,
'message': 'An error occurred',
'details': {}
'error_code': error_code,
'message': str(exc),
'details': exc.detail,
}
if isinstance(exc, APIException):
response_data['message'] = exc.detail if isinstance(exc.detail, str) else "Validation error"
if isinstance(exc.detail, str):
message = exc.detail
elif isinstance(exc.detail, dict) and ('message' in exc.detail or 'string' in exc.detail):
message = exc.detail.get('message') or exc.detail.get('string')
else:
message = error_code
response_data['message'] = message
response_data['details'] = exc.detail if isinstance(exc.detail, dict) else {}
response.data = response_data
@ -44,8 +62,24 @@ class ErrorMiddleware:
{
"success": False,
"status_code": 500,
'error_code': 500,
"message": "Internal server error",
"details": str(exception) # فقط در حالت توسعه! در تولید بهتر است لاگ شود.
},
status=500
)
)
from rest_framework.exceptions import APIException
from rest_framework import status
from django.utils.translation import gettext_lazy as _
class UnprocessableEntity(APIException):
status_code = 422
default_detail = 'The request was well-formed but cannot be processed due to semantic errors.'
default_code = 'unprocessable_entity'
class StatusError(APIException):
status_code = status.HTTP_503_SERVICE_UNAVAILABLE
default_ = _('SERVICE_UNAVAILABLE')
default_code = 'service_unavailable'