Merge pull request #10 from AmanTahiliani/aman-backend-ranking

Aman backend ranking
This commit is contained in:
Sahej Panag
2024-04-13 00:59:18 -04:00
committed by GitHub
9 changed files with 165 additions and 5 deletions

View File

@@ -0,0 +1,23 @@
# Generated by Django 4.2.11 on 2024-04-12 20:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("api", "0005_file_created_at"),
]
operations = [
migrations.AddField(
model_name="file",
name="points",
field=models.IntegerField(default=0),
),
migrations.AddField(
model_name="peeruser",
name="points",
field=models.IntegerField(default=0),
),
]

View File

@@ -0,0 +1,32 @@
# Generated by Django 4.2.11 on 2024-04-12 21:47
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("api", "0006_file_points_peeruser_points"),
]
operations = [
migrations.RemoveField(
model_name="file",
name="points",
),
migrations.AddField(
model_name="file",
name="downvotes",
field=models.ManyToManyField(
related_name="downvoted_file", to=settings.AUTH_USER_MODEL
),
),
migrations.AddField(
model_name="file",
name="upvotes",
field=models.ManyToManyField(
related_name="upvoted_file", to=settings.AUTH_USER_MODEL
),
),
]

View File

@@ -6,6 +6,7 @@ from django.db import models
class PeerUser(AbstractUser): class PeerUser(AbstractUser):
ip_address = models.GenericIPAddressField(blank=True, null=True) ip_address = models.GenericIPAddressField(blank=True, null=True)
last_poll = models.DateTimeField(auto_now_add=True) last_poll = models.DateTimeField(auto_now_add=True)
points = models.IntegerField(default=0, blank=False)
class Topic(models.Model): class Topic(models.Model):
@@ -57,6 +58,13 @@ class File(models.Model):
Course, on_delete=models.SET_NULL, null=True, related_name="files" Course, on_delete=models.SET_NULL, null=True, related_name="files"
) )
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
upvotes = models.ManyToManyField(PeerUser, related_name="upvoted_file")
downvotes = models.ManyToManyField(PeerUser, related_name="downvoted_file")
@property
def points(self):
return self.upvotes.count() - self.downvotes.count()
def __str__(self): def __str__(self):
return self.filename return self.filename

View File

@@ -10,7 +10,7 @@ class LoginSerializer(serializers.Serializer):
class UserSerializer(serializers.ModelSerializer): class UserSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = PeerUser model = PeerUser
fields = ["id", "username", "email", "ip_address"] fields = ["id", "username", "email", "ip_address", "points"]
class TopicSerializer(serializers.ModelSerializer): class TopicSerializer(serializers.ModelSerializer):

View File

@@ -54,7 +54,17 @@ urlpatterns = [
name="course-detail", name="course-detail",
), ),
path("api/files/", views.FileListCreateAPIView.as_view(), name="file-list"), path("api/files/", views.FileListCreateAPIView.as_view(), name="file-list"),
path(
"api/files/<int:file_id>/upvote/",
views.UpvoteFile.as_view(),
name="upvote-file",
),
path(
"api/files/<int:file_id>/downvote/",
views.DownvoteFile.as_view(),
name="downvote-file",
),
path("api/files/<int:pk>/", views.FileDetailAPIView.as_view(), name="file-detail"), path("api/files/<int:pk>/", views.FileDetailAPIView.as_view(), name="file-detail"),
path("api/files/filter/", views.FileFilterView.as_view(), name="file-filter-view"),
path("api/register/", views.RegisterFile.as_view(), name="file-register"), path("api/register/", views.RegisterFile.as_view(), name="file-register"),
path("api/files/filter/", views.FileFilterView.as_view(), name="file-filter-view"),
] ]

View File

@@ -7,6 +7,7 @@ from rest_framework.views import APIView
from rest_framework.authentication import TokenAuthentication from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from api.utils.get_client_ip import get_client_ip from api.utils.get_client_ip import get_client_ip
from django.utils import timezone
class LoginView(APIView): class LoginView(APIView):
@@ -18,6 +19,7 @@ class LoginView(APIView):
user = authenticate(username=username, password=password) user = authenticate(username=username, password=password)
if user: if user:
token, _ = Token.objects.get_or_create(user=user) token, _ = Token.objects.get_or_create(user=user)
user.last_poll = timezone.now()
response = Response({"token": token.key}, status=status.HTTP_200_OK) response = Response({"token": token.key}, status=status.HTTP_200_OK)
response.set_cookie("token", token.key) response.set_cookie("token", token.key)
return response return response
@@ -66,6 +68,7 @@ class PollOnlineView(APIView):
user = request.user user = request.user
ip_address = get_client_ip(request) ip_address = get_client_ip(request)
user.ip_address = ip_address user.ip_address = ip_address
user.last_poll = timezone.now()
user.save() user.save()
return Response( return Response(
{ {

View File

@@ -1,3 +1,6 @@
from django.utils import timezone
def get_client_ip(request): def get_client_ip(request):
x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR") x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
if x_forwarded_for: if x_forwarded_for:
@@ -11,4 +14,5 @@ def update_user_ip(request):
user = request.user user = request.user
ip_address = get_client_ip(request) ip_address = get_client_ip(request)
user.ip_address = ip_address user.ip_address = ip_address
user.last_poll = timezone.now()
user.save() user.save()

View File

@@ -5,10 +5,12 @@ from api.serializers import (
ProfessorSerializer, ProfessorSerializer,
SemesterSerializer, SemesterSerializer,
TopicSerializer, TopicSerializer,
UserSerializer,
) )
from datetime import datetime, timedelta from datetime import datetime, timedelta
from django.contrib.auth import authenticate from django.contrib.auth import authenticate
from django.db import transaction from django.db import transaction
from django.utils import timezone
from rest_framework import generics, status from rest_framework import generics, status
from rest_framework.authentication import TokenAuthentication from rest_framework.authentication import TokenAuthentication
from rest_framework.authtoken.models import Token from rest_framework.authtoken.models import Token
@@ -105,6 +107,58 @@ class FileDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
class UpvoteFile(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
def post(self, request, file_id):
user = request.user
update_user_ip(request)
try:
file = File.objects.get(id=file_id)
if file.downvotes.contains(user):
file.downvotes.remove(user)
file.upvotes.add(user)
file.save()
return Response(
{"msg": f"Upvoted {file.filename}", "file_points": file.points},
status=status.HTTP_200_OK,
)
except Exception as e:
print(f"Error: {str(e)}")
return Response(
{"error": "Please enter valid file id"},
status=status.HTTP_400_BAD_REQUEST,
)
class DownvoteFile(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
def post(self, request, file_id):
user = request.user
update_user_ip(request)
try:
file = File.objects.get(id=file_id)
if file.upvotes.contains(user):
file.upvotes.remove(user)
file.downvotes.add(user)
file.save()
return Response(
{"msg": f"Downvoted {file.filename}", "file_points": file.points},
status=status.HTTP_200_OK,
)
except Exception as e:
print(f"Error: {str(e)}")
return Response(
{"error": "Please enter valid file id"},
status=status.HTTP_400_BAD_REQUEST,
)
class RegisterFile(APIView): class RegisterFile(APIView):
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
@@ -115,6 +169,7 @@ class RegisterFile(APIView):
data = request.data data = request.data
try: try:
with transaction.atomic(): with transaction.atomic():
user.last_poll = timezone.now()
required_fields = set( required_fields = set(
["filename", "topic", "semester", "professor", "course"] ["filename", "topic", "semester", "professor", "course"]
) )
@@ -166,7 +221,9 @@ class RegisterFile(APIView):
"course": file.course.name if file.course else None, "course": file.course.name if file.course else None,
"professor": file.professor.name if file.professor else None, "professor": file.professor.name if file.professor else None,
} }
user.points += 1
file.save() file.save()
user.save()
return Response( return Response(
response_data, response_data,
status=status.HTTP_201_CREATED, status=status.HTTP_201_CREATED,
@@ -178,9 +235,19 @@ class RegisterFile(APIView):
) )
from django.utils import timezone
from datetime import timedelta
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import File, PeerUser
from .serializers import FileSerializer
class FileFilterView(APIView): class FileFilterView(APIView):
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
def get(self, request, format=None): def get(self, request, format=None):
try: try:
# Extract filters from the query parameters # Extract filters from the query parameters
@@ -226,12 +293,25 @@ class FileFilterView(APIView):
# Filter files based on active peers in the past hour # Filter files based on active peers in the past hour
active_peer_ids = PeerUser.objects.filter( active_peer_ids = PeerUser.objects.filter(
last_poll__gte=datetime.now() - timedelta(hours=1) last_poll__gte=timezone.now() - timedelta(hours=1)
).values_list("id", flat=True) ).values_list("id", flat=True)
queryset = queryset.filter(peer_users__in=active_peer_ids).distinct() queryset = queryset.filter(peer_users__in=active_peer_ids).distinct()
# Sort files based on points column in descending order
queryset = queryset.order_by("-points")
# Serialize files
serializer = FileSerializer(queryset, many=True) serializer = FileSerializer(queryset, many=True)
# Loop through each serialized file to sort its peer_users
for file_data in serializer.data:
file_obj = File.objects.get(id=file_data["id"])
sorted_peer_users = sorted(
file_obj.peer_users.all(), key=lambda x: x.points, reverse=True
)
file_data["peer_users"] = UserSerializer(
sorted_peer_users, many=True
).data
return Response(serializer.data) return Response(serializer.data)
except Exception as e: except Exception as e:
return Response( return Response(

View File

@@ -137,4 +137,4 @@ CORS_ALLOW_ALL_ORIGINS = True
# CORS_ALLOWED_ORIGINS = [ # CORS_ALLOWED_ORIGINS = [
# "http://localhost:5173" # "http://localhost:5173"
# ] # ]
CORS_ALLOW_CREDENTIALS = True CORS_ALLOW_CREDENTIALS = True