feat: added promocode getting by id, added likes add/delete, code refactoring

This commit is contained in:
ITQ
2025-01-24 22:51:44 +03:00
parent fe2bc038a9
commit afc6a5cf09
5 changed files with 127 additions and 16 deletions
+8 -5
View File
@@ -2,6 +2,7 @@ import datetime
from collections import Counter
from http import HTTPStatus as status
from django.db import transaction
from django.db.models import Count, Q, Value
from django.db.models.functions import Coalesce
from django.http import HttpRequest, HttpResponse
@@ -119,10 +120,11 @@ def create_promocode(
validate_unique=False,
)
target_obj.save()
with transaction.atomic():
target_obj.save()
promocode_obj.target = target_obj
promocode_obj.save()
promocode_obj.target = target_obj
promocode_obj.save()
return status.CREATED, schemas.CreatePromocodeOut(id=promocode_obj.id)
@@ -271,9 +273,10 @@ def patch_promocode(
setattr(promocode.target, field, value)
if "country" in target_data:
promocode.target.country_raw = target_data["country"]
promocode.target.save()
promocode.save()
with transaction.atomic():
promocode.target.save()
promocode.save()
return status.OK, utils.map_promocode_to_schema(promocode)
+8
View File
@@ -88,3 +88,11 @@ class PromocodeViewOut(Schema):
is_liked_by_user: bool
like_count: int
comment_count: int
class PromocodeLikeOut(Schema):
status: str = "ok"
class PromocodeRemoveLikeOut(Schema):
status: str = "ok"
+106 -9
View File
@@ -1,15 +1,17 @@
import contextlib
from http import HTTPStatus as status
from django.db.models import Count, Exists, OuterRef, Q
from django.http import HttpRequest, HttpResponse
from ninja import Query, Router
from ninja.errors import AuthenticationError
from ninja.errors import AuthenticationError, HttpError
from api.v1 import schemas as global_schemas
from api.v1.auth import UserAuth
from api.v1.user import schemas, utils
from apps.promo.models import Promocode, PromocodeActivation, PromocodeLike
from apps.user.models import User
from config.errors import UniqueConstraintError
router = Router(tags=["user"])
@@ -81,10 +83,10 @@ def signin(
},
exclude_none=True,
)
def get_profile(request: HttpRequest) -> schemas.ViewUserOut:
def get_profile(request: HttpRequest) -> tuple[int, schemas.ViewUserOut]:
user = request.auth
return utils.map_user_to_schema(user)
return status.OK, utils.map_user_to_schema(user)
@router.patch(
@@ -98,7 +100,7 @@ def get_profile(request: HttpRequest) -> schemas.ViewUserOut:
)
def patch_profile(
request: HttpRequest, patched_fields: schemas.PatchUserIn
) -> schemas.ViewUserOut:
) -> tuple[int, schemas.ViewUserOut]:
user = request.auth
patch_data = patched_fields.dict(exclude_unset=True)
@@ -107,7 +109,7 @@ def patch_profile(
user.save()
return utils.map_user_to_schema(user)
return status.OK, utils.map_user_to_schema(user)
@router.get(
@@ -123,10 +125,10 @@ def feed(
request: HttpRequest,
filters: Query[schemas.PromocodeFeedFilters],
response: HttpResponse,
) -> list[schemas.PromocodeViewOut]:
) -> tuple[status.OK, list[schemas.PromocodeViewOut]]:
user: User = request.auth
promocodes = Promocode.objects
promocodes = Promocode.objects.select_related("target")
promocodes = promocodes.filter(
Q(
@@ -138,7 +140,7 @@ def feed(
)
)
promocodes = promocodes.annotate(
promocodes = promocodes.prefetch_related("likes", "comments").annotate(
like_count=Count("likes"),
comment_count=Count("comments"),
is_liked_by_user=Exists(
@@ -166,6 +168,101 @@ def feed(
promocodes = promocodes[filters.offset : filters.offset + filters.limit]
return [
return status.OK, [
utils.map_promocode_to_schema(promocode) for promocode in promocodes
]
@router.get(
"/promo/{promocode_id}",
auth=UserAuth(),
response={
status.OK: schemas.PromocodeViewOut,
status.BAD_REQUEST: global_schemas.ValidationError,
},
exclude_none=True,
)
def get_promocode(
request: HttpRequest, promocode_id: str
) -> tuple[status.OK, schemas.PromocodeViewOut]:
user: User = request.auth
promocodes = Promocode.objects.filter(id=promocode_id)
if not promocodes.exists():
raise HttpError(status.NOT_FOUND, status.NOT_FOUND.phrase)
promocodes = (
promocodes.select_related("business")
.prefetch_related("likes", "comments")
.annotate(
like_count=Count("likes"),
comment_count=Count("comments"),
is_liked_by_user=Exists(
PromocodeLike.objects.filter(
promocode=OuterRef("pk"), user=user
)
),
is_activated_by_user=Exists(
PromocodeActivation.objects.filter(
promocode=OuterRef("pk"), user=user
)
),
)
)
promocode = promocodes.first()
return status.OK, utils.map_promocode_to_schema(promocode)
@router.post(
"/promo/{promocode_id}/like",
auth=UserAuth(),
response={
status.OK: schemas.PromocodeLikeOut,
status.BAD_REQUEST: global_schemas.ValidationError,
},
exclude_none=True,
)
def add_like(
request: HttpRequest, promocode_id: str
) -> tuple[status.OK, schemas.PromocodeViewOut]:
user: User = request.auth
promocodes = Promocode.objects.filter(id=promocode_id)
if not promocodes.exists():
raise HttpError(status.NOT_FOUND, status.NOT_FOUND.phrase)
with contextlib.suppress(UniqueConstraintError):
PromocodeLike.objects.create(promocode=promocodes.first(), user=user)
return status.OK, schemas.PromocodeLikeOut()
@router.delete(
"/promo/{promocode_id}/like",
auth=UserAuth(),
response={
status.OK: schemas.PromocodeRemoveLikeOut,
status.BAD_REQUEST: global_schemas.ValidationError,
},
exclude_none=True,
)
def delete_like(
request: HttpRequest, promocode_id: str
) -> tuple[status.OK, schemas.PromocodeViewOut]:
user: User = request.auth
promocodes = Promocode.objects.filter(id=promocode_id)
if not promocodes.exists():
raise HttpError(status.NOT_FOUND, status.NOT_FOUND.phrase)
with contextlib.suppress(PromocodeLike.DoesNotExist):
PromocodeLike.objects.get(
promocode=promocodes.first(), user=user
).delete()
return status.OK, schemas.PromocodeLikeOut()
@@ -1,4 +1,4 @@
# Generated by Django 5.1.5 on 2025-01-23 17:54
# Generated by Django 5.1.5 on 2025-01-24 18:26
import apps.promo.validators
import django.core.validators
@@ -86,7 +86,7 @@ class Migration(migrations.Migration):
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='liked_promocodes', to='user.user')),
],
options={
'abstract': False,
'unique_together': {('promocode', 'user')},
},
),
]
+3
View File
@@ -209,3 +209,6 @@ class PromocodeLike(BaseModel):
user = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="liked_promocodes"
)
class Meta:
unique_together = ("promocode", "user")