feat: added promocode activation

also code reformatting and bug fixes
This commit is contained in:
ITQ
2025-01-26 11:33:03 +03:00
parent 43baa2af5c
commit 545201e4dd
11 changed files with 218 additions and 99 deletions
-73
View File
@@ -1,73 +0,0 @@
from datetime import datetime
from http import HTTPStatus as status
from typing import ClassVar
import httpx
from django.core.cache import cache
from django.utils import timezone
class AntifraudServiceInteractor:
HEADERS: ClassVar[dict[str, str]] = {"Content-Type": "application/json"}
CACHE_PREFIX = "antifraud_cache"
def __init__(self, endpoint: str) -> None:
self.antifraud_endpoint = f"{endpoint}/api/validate"
@classmethod
def get_cache_key(cls, user_email: str, promo_id: str) -> None:
return f"{cls.CACHE_PREFIX}:{user_email}:{promo_id}"
@classmethod
def is_cache_valid(cls, cache_until: str) -> bool:
if cache_until:
return (
datetime.fromisoformat(cache_until).replace(
tzinfo=timezone.utc,
)
> timezone.now()
)
return False
@classmethod
def validate(cls, user_email: str, promo_id: str) -> dict[str, bool | str]:
cache_key = cls.get_cache_key(user_email, promo_id)
cached_result = cache.get(cache_key)
if cached_result and cls.is_cache_valid(
cached_result.get("cache_until"),
):
return cached_result
payload = {"user_email": user_email, "promo_id": promo_id}
try:
with httpx.Client(timeout=5) as client:
response = client.post(
cls.antifraud_endpoint,
json=payload,
headers=cls.HEADERS,
)
if response.status_code == status.OK:
result = response.json()
if "cache_until" in result:
cache.set(cache_key, result)
return result
retry_response = client.post(
cls.antifraud_endpoint,
json=payload,
headers=cls.HEADERS,
)
if retry_response.status_code == status.OK:
result = retry_response.json()
if "cache_until" in result:
cache.set(cache_key, result)
return result
except httpx.HTTPError:
pass
return {"ok": False}
@@ -10,7 +10,7 @@ class AntifraudHealthCheck(BaseHealthCheckBackend):
def check_status(self) -> None:
try:
response = httpx.get(f"{settings.ANTIFRAUD_ENDPOINT}/api/ping")
response = httpx.get(f"{settings.ANTIFRAUD_ADDRESS}/api/ping")
if response.status_code >= status.INTERNAL_SERVER_ERROR:
self.add_error("Antifraud service is unaccessible")
except httpx.HTTPError:
@@ -0,0 +1,112 @@
import time
from datetime import datetime
from http import HTTPStatus as status
from typing import ClassVar
import httpx
from django.conf import settings
from django.core.cache import cache
from django.utils import timezone
from pytz import timezone as tz
logger = settings.LOGGER
class AntifraudServiceInteractor:
HEADERS: ClassVar[dict[str, str]] = {"Content-Type": "application/json"}
CACHE_PREFIX = "antifraud_cache"
ANTIFRAUD_ENDPOINT = f"{settings.ANTIFRAUD_ADDRESS}/api/validate"
RETRY_COUNT: ClassVar[int] = 2
@classmethod
def get_cache_key(cls, user_email: str, promo_id: str) -> str:
return f"{cls.CACHE_PREFIX}:{user_email}:{promo_id}"
@classmethod
def is_cache_valid(cls, cache_until: str) -> bool:
if cache_until:
try:
cache_expiry = datetime.fromisoformat(cache_until).astimezone(
tz(settings.TIME_ZONE)
)
return cache_expiry > timezone.now()
except ValueError:
return False
return False
@staticmethod
def _make_request(
client: httpx.Client,
url: str,
payload: dict[str, str],
headers: dict[str, str],
retries: int,
) -> httpx.Response | None:
for attempt in range(1, retries + 1):
start_time = time.time()
try:
response = client.post(url, json=payload, headers=headers)
request_time = time.time() - start_time
logger.info(
"Attempt %d: Request to %s took %s seconds",
attempt,
url,
request_time,
)
if response.status_code == status.OK:
return response
logger.warning(
"Attempt %d failed with status %d",
attempt,
response.status_code,
)
except httpx.HTTPError:
logger.exception(
"Attempt %d: HTTP error during request to %s",
attempt,
url,
)
logger.exception("All %d attempts to %s failed", retries, url)
return None
@classmethod
def validate(cls, user_email: str, promo_id: str) -> dict[str, bool | str]:
cache_key = cls.get_cache_key(user_email, promo_id)
cached_result = cache.get(cache_key)
if cached_result and cls.is_cache_valid(
cached_result.get("cache_until")
):
return cached_result
payload = {"user_email": user_email, "promo_id": promo_id}
try:
logger.info("Trying to validate antifraud")
with httpx.Client(timeout=5) as client:
response = cls._make_request(
client,
cls.ANTIFRAUD_ENDPOINT,
payload,
cls.HEADERS,
retries=cls.RETRY_COUNT,
)
if response:
logger.info("Antifraud works perfectly")
result = response.json()
if "cache_until" in result:
cache.set(cache_key, result)
return result
except Exception as e:
logger.exception(
"Unexpected error during antifraud validation: %s",
e, # noqa: TRY401
)
return {"ok": False}