mirror of
https://github.com/AmanTahiliani/PeerNotes.git
synced 2026-08-07 11:55:12 -04:00
Merge pull request #10 from AmanTahiliani/aman-backend-ranking
Aman backend ranking
This commit is contained in:
23
backend/api/migrations/0006_file_points_peeruser_points.py
Normal file
23
backend/api/migrations/0006_file_points_peeruser_points.py
Normal 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),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -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
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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"),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user