Skip to content

Commit

Permalink
style(pre-commit): perform pre commit to style codes
Browse files Browse the repository at this point in the history
  • Loading branch information
sepehr-akbarzadeh committed Oct 17, 2024
1 parent d375343 commit bcb0979
Show file tree
Hide file tree
Showing 21 changed files with 171 additions and 174 deletions.
13 changes: 6 additions & 7 deletions sage_invoice/api/helpers/versioning.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
from rest_framework.versioning import BaseVersioning
from rest_framework.exceptions import NotFound
from rest_framework.versioning import BaseVersioning

SUPPORTED_VERSIONS = ["1.0"]

SUPPORTED_VERSIONS = [
'1.0'
]

class HeaderVersioning(BaseVersioning):
def determine_version(self, request, *args, **kwargs):
# Get the version from the 'X-API-Version' header
accept_header = request.META.get('HTTP_X_API_VERSION', '')
accept_header = request.META.get("HTTP_X_API_VERSION", "")

# Check if the version header contains 'v'
if 'v' in accept_header:
version = accept_header.split('v')[-1].split('+')[0]
if "v" in accept_header:
version = accept_header.split("v")[-1].split("+")[0]
else:
version = None

Expand Down
49 changes: 30 additions & 19 deletions sage_invoice/api/mixins/exception.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import logging
import uuid

from django.utils.timezone import now
from rest_framework.views import exception_handler
from rest_framework.exceptions import ValidationError, NotFound, APIException, NotAcceptable
from rest_framework import status
from rest_framework.exceptions import (
APIException,
NotAcceptable,
NotFound,
ValidationError,
)
from rest_framework.response import Response
from rest_framework.views import exception_handler

# Get the logger instance
logger = logging.getLogger(__name__)


class ErrorHandlingMixin:
"""
Mixin to provide consistent error handling across APIs,
Mixin to provide consistent error handling across APIs,
including structured error responses, logging, and trace IDs.
"""

Expand All @@ -25,9 +32,9 @@ def handle_exception(self, exc):

# Generate a unique trace ID for this request
trace_id = str(uuid.uuid4())

# Path from the current request
path = self.request.path if hasattr(self, 'request') else 'unknown'
path = self.request.path if hasattr(self, "request") else "unknown"

# Default error structure
error_response = {
Expand All @@ -36,32 +43,32 @@ def handle_exception(self, exc):
"details": [],
"path": path,
"traceId": trace_id,
"timestamp": now().isoformat()
"timestamp": now().isoformat(),
}

# Handle specific exceptions for better detail
if isinstance(exc, ValidationError):
error_response['code'] = "VALIDATION_ERROR"
error_response['message'] = "Invalid input parameters"
error_response['details'] = [
error_response["code"] = "VALIDATION_ERROR"
error_response["message"] = "Invalid input parameters"
error_response["details"] = [
{"field": field, "message": msg[0] if isinstance(msg, list) else msg}
for field, msg in exc.detail.items()
]
status_code = status.HTTP_400_BAD_REQUEST

elif isinstance(exc, NotFound):
error_response['code'] = "NOT_FOUND"
error_response['message'] = str(exc)
error_response["code"] = "NOT_FOUND"
error_response["message"] = str(exc)
status_code = status.HTTP_404_NOT_FOUND

elif isinstance(exc, NotAcceptable):
error_response['code'] = "NOT_ACCEPTABLE"
error_response['message'] = str(exc)
error_response["code"] = "NOT_ACCEPTABLE"
error_response["message"] = str(exc)
status_code = status.HTTP_406_NOT_ACCEPTABLE

elif isinstance(exc, APIException):
error_response['code'] = exc.get_codes() if exc.get_codes() else "API_ERROR"
error_response['message'] = str(exc)
error_response["code"] = exc.get_codes() if exc.get_codes() else "API_ERROR"
error_response["message"] = str(exc)
status_code = exc.status_code

else:
Expand All @@ -77,16 +84,20 @@ def handle_exception(self, exc):
response = Response(error_response, status=status_code)

# Log the error details with trace ID for correlation
logger.error(f"Error occurred [traceId={trace_id}] at {path}: {exc}", exc_info=True)
logger.error(
f"Error occurred [traceId={trace_id}] at {path}: {exc}", exc_info=True
)

return response

def get_exception_handler_context(self):
"""
This method returns the context that will be passed to the DRF exception handler.
This method returns the context that will be passed to the DRF exception
handler.
It's useful to provide additional request-related context (like view, request, args).
"""
return {
'view': self,
'request': self.request,
"view": self,
"request": self.request,
}
4 changes: 2 additions & 2 deletions sage_invoice/api/serializers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from .expense import ExpenseSerializer
from .category import CategorySerializer
from .column import ColumnSerializer
from .item import ItemSerializer
from .expense import ExpenseSerializer
from .invoice import InvoiceSerializer
from .item import ItemSerializer
20 changes: 6 additions & 14 deletions sage_invoice/api/serializers/category.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,20 @@
# serializers.py
from rest_framework import serializers

from sage_invoice.models import Category


class CategorySerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name='category-detail',
lookup_field='slug'
view_name="category-detail", lookup_field="slug"
)
invoices = serializers.HyperlinkedRelatedField(
many=True,
view_name='invoice-detail',
lookup_field='slug',
read_only=True
many=True, view_name="invoice-detail", lookup_field="slug", read_only=True
)

class Meta:
model = Category
fields = (
"url",
"title",
"description",
"invoices"
)
fields = ("url", "title", "description", "invoices")
extra_kwargs = {
'url': {'lookup_field': 'slug'},
}
"url": {"lookup_field": "slug"},
}
11 changes: 6 additions & 5 deletions sage_invoice/api/serializers/column.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
from rest_framework import serializers

from sage_invoice.models import Column


class ColumnSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Column
fields = '__all__'
fields = "__all__"
lookup_field = "id"
extra_kwargs = {
'url': {'lookup_field': 'id'},
'invoice': {'lookup_field': "slug"},
'item': {'lookup_field': "id"},
}
"url": {"lookup_field": "id"},
"invoice": {"lookup_field": "slug"},
"item": {"lookup_field": "id"},
}
9 changes: 5 additions & 4 deletions sage_invoice/api/serializers/expense.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
# serializers.py
from rest_framework import serializers

from sage_invoice.models import Expense


class ExpenseSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Expense
fields = '__all__'
fields = "__all__"
lookup_field = "id"
extra_kwargs = {
'url': {'lookup_field': 'id'},
'invoice': {'lookup_field': "slug"}
}
"url": {"lookup_field": "id"},
"invoice": {"lookup_field": "slug"},
}
89 changes: 44 additions & 45 deletions sage_invoice/api/serializers/invoice.py
Original file line number Diff line number Diff line change
@@ -1,46 +1,45 @@
from rest_framework import serializers

from sage_invoice.api.serializers import ItemSerializer, CategorySerializer, ColumnSerializer, ExpenseSerializer
from sage_invoice.models import Invoice, Category
from sage_invoice.api.serializers import (
CategorySerializer,
ColumnSerializer,
ExpenseSerializer,
ItemSerializer,
)
from sage_invoice.models import Category, Invoice


class ContactFieldSerializer(serializers.Serializer):
"""
Serializer to validate the structure of the contacts field (either phone or email).
Serializer to validate the structure of the contacts field (either phone or
email).
"""

phone = serializers.RegexField(
regex=r'^\d{10,15}$',
required=False,
help_text="Phone number should only contain digits and be 10-15 characters long."
)
email = serializers.EmailField(
regex=r"^\d{10,15}$",
required=False,
help_text="Valid email format."
help_text="Phone number should only contain digits and be 10-15 characters long.",
)
email = serializers.EmailField(required=False, help_text="Valid email format.")

def validate(self, data):
"""
Ensure at least one of 'phone' or 'email' is provided.
"""
if not data.get('phone') and not data.get('email'):
"""Ensure at least one of 'phone' or 'email' is provided."""
if not data.get("phone") and not data.get("email"):
raise serializers.ValidationError("Either phone or email must be provided.")
return data


class NoteFieldSerializer(serializers.Serializer):
"""
Serializer to validate the structure of the notes field (additional fields).
"""
"""Serializer to validate the structure of the notes field (additional fields)."""

label = serializers.CharField()
content = serializers.CharField()


class InvoiceSerializer(serializers.HyperlinkedModelSerializer):
contacts = ContactFieldSerializer(required=False)
notes = serializers.ListField(
child=serializers.DictField(
child=serializers.CharField()
),
required=False
child=serializers.DictField(child=serializers.CharField()), required=False
)
category = CategorySerializer(read_only=True)
items = ItemSerializer(many=True, read_only=True)
Expand All @@ -50,31 +49,31 @@ class InvoiceSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Invoice
fields = [
'url',
'slug',
'invoice_date',
'customer_name',
'tracking_code',
'contacts',
'status',
'receipt',
'notes',
'currency',
'due_date',
'template_choice',
'logo',
'signature',
'stamp',
'category',
'items',
'columns',
'expense',
"url",
"slug",
"invoice_date",
"customer_name",
"tracking_code",
"contacts",
"status",
"receipt",
"notes",
"currency",
"due_date",
"template_choice",
"logo",
"signature",
"stamp",
"category",
"items",
"columns",
"expense",
]
extra_kwargs = {
'url': {'lookup_field': 'slug'},
'categories': {'lookup_field': 'slug'},
'items': {'lookup_field': 'id'},
'columns': {'lookup_field': 'id'},
'expense': {'lookup_field': 'id'},
"url": {"lookup_field": "slug"},
"categories": {"lookup_field": "slug"},
"items": {"lookup_field": "id"},
"columns": {"lookup_field": "id"},
"expense": {"lookup_field": "id"},
}
read_only_fields = ['slug']
read_only_fields = ["slug"]
7 changes: 4 additions & 3 deletions sage_invoice/api/serializers/item.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
# serializers.py
from rest_framework import serializers

from sage_invoice.models import Item


class ItemSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Item
fields = '__all__'
fields = "__all__"
lookup_field = "id"
extra_kwargs = {
'url': {'lookup_field': 'id'},
'invoice': {'lookup_field': "slug"}
"url": {"lookup_field": "id"},
"invoice": {"lookup_field": "slug"},
}
18 changes: 9 additions & 9 deletions sage_invoice/api/urls.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
from django.urls import path, include
from django.urls import include, path
from rest_framework.routers import DefaultRouter

from .views import (
CategoryViewSet,
ColumnViewSet,
ExpenseViewSet,
InvoiceViewSet,
ItemViewSet,
CategoryViewSet,
ColumnViewSet
)

router = DefaultRouter()
router.register(r'expenses', ExpenseViewSet)
router.register(r'invoices', InvoiceViewSet)
router.register(r'items', ItemViewSet)
router.register(r'categories', CategoryViewSet)
router.register(r'columns', ColumnViewSet)
router.register(r"expenses", ExpenseViewSet)
router.register(r"invoices", InvoiceViewSet)
router.register(r"items", ItemViewSet)
router.register(r"categories", CategoryViewSet)
router.register(r"columns", ColumnViewSet)

urlpatterns = [
path('', include(router.urls)),
path("", include(router.urls)),
]
Loading

0 comments on commit bcb0979

Please sign in to comment.