From 6fa037390c8456156e6b735289e0ee85371bd707 Mon Sep 17 00:00:00 2001 From: Egor fureunoir Gorbunov Date: Wed, 15 Oct 2025 14:25:10 +0300 Subject: [PATCH] Features: 1) Add `get_gateways_integrations` utility for payment gateway integrations; 2) Add `get_vendors_integrations` utility for vendor integrations; 3) Add `version` API endpoint to return eVibes version; 4) Implement `__str__` method for `AbstractVendor`; Fixes: 1) Update return type of `create_object` to `Any`; Extra: 1) Remove unused fields (`icon`, `priority`, `hide`) from `blog.apps`; 2) Update API URLs to include `version` endpoint; 3) Miscellaneous cleanup and comments. --- blog/apps.py | 3 --- core/utils/vendors.py | 16 ++++++++++++++++ core/vendors/__init__.py | 3 +++ core/views.py | 10 ++++++++++ evibes/api_urls.py | 2 ++ evibes/utils/misc.py | 2 +- payments/utils/gateways.py | 16 ++++++++++++++++ 7 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 core/utils/vendors.py create mode 100644 payments/utils/gateways.py diff --git a/blog/apps.py b/blog/apps.py index 2783a0aa..689b2aaf 100644 --- a/blog/apps.py +++ b/blog/apps.py @@ -6,9 +6,6 @@ class BlogConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" name = "blog" verbose_name = _("blog") - icon = "fa fa-solid fa-book" - priority = 86 - hide = False # noinspection PyUnresolvedReferences def ready(self) -> None: diff --git a/core/utils/vendors.py b/core/utils/vendors.py new file mode 100644 index 00000000..f68a4c31 --- /dev/null +++ b/core/utils/vendors.py @@ -0,0 +1,16 @@ +from typing import Type + +from core.models import Vendor +from core.vendors import AbstractVendor +from evibes.utils.misc import create_object + + +def get_vendors_integrations(name: str | None = None) -> list[Type[AbstractVendor]]: + vendors_integrations: list[Type[AbstractVendor]] = [] + vendors = Vendor.objects.filter(is_active=True, name=name) if name else Vendor.objects.filter(is_active=True) + for vendor in vendors: + if vendor.integration_path: + module_name = ".".join(vendor.integration_path.split(".")[:-1]) + class_name = vendor.integration_path.split(".")[-1] + vendors_integrations.append(create_object(module_name, class_name)) + return vendors_integrations diff --git a/core/vendors/__init__.py b/core/vendors/__init__.py index da68d537..a460d850 100644 --- a/core/vendors/__init__.py +++ b/core/vendors/__init__.py @@ -84,6 +84,9 @@ class AbstractVendor: self.currency = currency self.blocked_attributes: list[Any] = [] + def __str__(self) -> str: + return self.vendor_name or self.get_vendor_instance().name + @staticmethod def chunk_data(data: list[Any] | None = None, num_chunks: int = 20) -> list[list[Any]] | list[Any]: if not data: diff --git a/core/views.py b/core/views.py index 68396451..a7b4a9aa 100644 --- a/core/views.py +++ b/core/views.py @@ -387,3 +387,13 @@ index.__doc__ = _( # type: ignore [assignment] "admin interface index page. It uses Django's `redirect` function for handling " "the HTTP redirection." ) + + +def version(request: HttpRequest, *args, **kwargs) -> HttpResponse: + return JsonResponse(camelize({"version": settings.EVIBES_VERSION}), status=200) + + +# noinspection PyTypeChecker +version.__doc__ = _( # type: ignore [assignment] + "Returns current version of the eVibes. " +) diff --git a/evibes/api_urls.py b/evibes/api_urls.py index 016efca4..b7ee3cd1 100644 --- a/evibes/api_urls.py +++ b/evibes/api_urls.py @@ -13,6 +13,7 @@ from core.views import ( CustomSwaggerView, favicon_view, index, + version, ) from evibes.settings import SPECTACULAR_PLATFORM_SETTINGS @@ -39,6 +40,7 @@ urlpatterns = [ path(r"i18n/", include("django.conf.urls.i18n")), path(r"favicon.ico", favicon_view), path(r"", index), + path(r"", version), path(r"", include("core.api_urls", namespace="core")), path(r"auth/", include("vibes_auth.urls", namespace="vibes_auth")), path(r"payments/", include("payments.urls", namespace="payments")), diff --git a/evibes/utils/misc.py b/evibes/utils/misc.py index 63c60fe3..4768de44 100644 --- a/evibes/utils/misc.py +++ b/evibes/utils/misc.py @@ -2,7 +2,7 @@ from importlib import import_module from typing import Any -def create_object(module_name: str, class_name: str, *args: list[Any], **kwargs: dict[Any, Any]) -> object: +def create_object(module_name: str, class_name: str, *args: list[Any], **kwargs: dict[Any, Any]) -> Any: module = import_module(module_name) cls = getattr(module, class_name) diff --git a/payments/utils/gateways.py b/payments/utils/gateways.py new file mode 100644 index 00000000..522adc68 --- /dev/null +++ b/payments/utils/gateways.py @@ -0,0 +1,16 @@ +from typing import Type + +from evibes.utils.misc import create_object +from payments.gateways import AbstractGateway +from payments.models import Gateway + + +def get_gateways_integrations(name: str | None = None) -> list[Type[AbstractGateway]]: + gateways_integrations: list[Type[AbstractGateway]] = [] + gateways = Gateway.objects.filter(is_active=True, name=name) if name else Gateway.objects.filter(is_active=True) + for gateway in gateways: + if gateway.integration_path: + module_name = ".".join(gateway.integration_path.split(".")[:-1]) + class_name = gateway.integration_path.split(".")[-1] + gateways_integrations.append(create_object(module_name, class_name)) + return gateways_integrations