Feat: [#88] 24시간 내 조회수 중복 방지

This commit is contained in:
sm4640
2025-08-21 00:31:04 +09:00
parent b5476d9cb0
commit 3152346ec7
2 changed files with 34 additions and 3 deletions

View File

@@ -7,6 +7,11 @@ from portfolios.models import Portfolio
from projects.serializers import ProjectNocodetoolSerializer
from portfolios.serializers import PortfolioNocodetoolSerializer
from django.utils import timezone
from django.db.models import F
from django_redis import get_redis_connection
NOCODETOOL_MODEL_MAP = {
'project': Project,
'portfolio': Portfolio,
@@ -27,3 +32,26 @@ class NocodetoolObjectMapService:
def mapping_model_serializer(related_type: str):
return NOCODETOOL_SERIALIZER_MAP.get(related_type, None)
class NocodetoolHitService:
def hit_once(obj, request, ttl=60*60*24):
user_key = request.user.id if request.user.is_authenticated else request.session.session_key
if not user_key:
request.session.save()
user_key = request.session.session_key()
today = timezone.localdate().isoformat()
key = f"viewed:obj:{obj.id}:{today}"
redis_conn = get_redis_connection("default")
added = redis_conn.sadd(key, user_key)
if added:
if redis_conn.ttl(key) == -1:
redis_conn.expire(key, ttl)
obj.__class__.objects.filter(id=obj.id).update(view_count=F("view_count") + 1)
return True
return False

View File

@@ -7,8 +7,8 @@ from django.db import transaction
from .models import Code, Page, Element
from .serializers import CodeSerializer
from .permissions import IsOwnerOrMemberInCreateAndUpdateAndDelete
from .services import NocodetoolObjectMapService
from .permissions import IsOwnerOrMemberInCreateAndUpdateAndDelete, IsNotPublished
from .services import NocodetoolObjectMapService, NocodetoolHitService
from users.models import User
from portfolios.models import Portfolio
@@ -18,13 +18,16 @@ from bson import ObjectId
class NoCodeToolAPIView(APIView):
permission_classes = [IsAuthenticated, IsOwnerOrMemberInCreateAndUpdateAndDelete]
permission_classes = [IsAuthenticated, IsNotPublished, IsOwnerOrMemberInCreateAndUpdateAndDelete]
@transaction.atomic
def get(self, request):
related_type = request.query_params.get("type")
related_id = request.query_params.get("id")
code_id = None
if obj := NocodetoolObjectMapService.mapping_model_instance(related_type, related_id):
if obj.is_published:
NocodetoolHitService.hit_once(obj, request)
code_id = ObjectId(obj.code_id)
if not code_id: