Added changes for Malicious User reporting

This commit is contained in:
2024-04-20 20:10:40 -04:00
parent 7c81755cda
commit b9b405fba8
7 changed files with 186 additions and 22 deletions

View File

@@ -0,0 +1,57 @@
# Generated by Django 4.2.11 on 2024-04-20 23:10
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("api", "0007_remove_file_points_file_downvotes_file_upvotes"),
]
operations = [
migrations.CreateModel(
name="UserReport",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("description", models.TextField(max_length=300)),
(
"file",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="file_report",
to="api.file",
),
),
(
"reporting_user",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="user_report_generated",
to=settings.AUTH_USER_MODEL,
),
),
(
"user",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="user_report",
to=settings.AUTH_USER_MODEL,
),
),
],
),
]

View File

@@ -61,10 +61,28 @@ class File(models.Model):
upvotes = models.ManyToManyField(PeerUser, related_name="upvoted_file") upvotes = models.ManyToManyField(PeerUser, related_name="upvoted_file")
downvotes = models.ManyToManyField(PeerUser, related_name="downvoted_file") downvotes = models.ManyToManyField(PeerUser, related_name="downvoted_file")
@property @property
def points(self): def points(self):
return self.upvotes.count() - self.downvotes.count() return self.upvotes.count() - self.downvotes.count()
def __str__(self): def __str__(self):
return self.filename return self.filename
class UserReport(models.Model):
user = models.ForeignKey(
PeerUser, on_delete=models.SET_NULL, null=True, related_name="user_report"
)
reporting_user = models.ForeignKey(
PeerUser,
on_delete=models.SET_NULL,
null=True,
related_name="user_report_generated",
)
description = models.TextField(blank=False, null=False, max_length=300)
file = models.ForeignKey(
File, on_delete=models.CASCADE, null=True, related_name="file_report"
)
def __str__(self) -> str:
return f"{self.user}:{self.file}:{self.reporting_user}"

View File

@@ -46,4 +46,17 @@ class FileSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = File model = File
fields = "__all__" fields = [
"id",
"filename",
"points",
"original_author",
"peer_users",
"topic",
"professor",
"semester",
"course",
"created_at",
"upvotes",
"downvotes",
]

View File

@@ -65,6 +65,7 @@ urlpatterns = [
name="downvote-file", 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/report_user/", views.ReportUserView.as_view(), name="report-user"),
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"), path("api/files/filter/", views.FileFilterView.as_view(), name="file-filter-view"),
] ]

View File

@@ -6,7 +6,7 @@ from rest_framework.response import Response
from rest_framework.views import APIView 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, PollMiddleware
from django.utils import timezone from django.utils import timezone

View File

@@ -1,3 +1,4 @@
from typing import Any
from django.utils import timezone from django.utils import timezone
@@ -16,3 +17,15 @@ def update_user_ip(request):
user.ip_address = ip_address user.ip_address = ip_address
user.last_poll = timezone.now() user.last_poll = timezone.now()
user.save() user.save()
class PollMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
print("Updating user last online and IP address")
update_user_ip(request)
response = self.get_response(request)
return response

View File

@@ -1,4 +1,4 @@
from api.models import Course, File, Professor, Semester, Topic, PeerUser from api.models import Course, File, Professor, Semester, Topic, PeerUser, UserReport
from api.serializers import ( from api.serializers import (
CourseSerializer, CourseSerializer,
FileSerializer, FileSerializer,
@@ -7,13 +7,13 @@ from api.serializers import (
TopicSerializer, TopicSerializer,
UserSerializer, UserSerializer,
) )
from datetime import datetime, timedelta from datetime import 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.db.models import Count, Value, F, IntegerField
from django.utils import timezone 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.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.views import APIView from rest_framework.views import APIView
@@ -235,15 +235,6 @@ 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]
@@ -251,6 +242,7 @@ class FileFilterView(APIView):
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
update_user_ip(request)
topic_id = request.query_params.get("topic") topic_id = request.query_params.get("topic")
professor_id = request.query_params.get("professor") professor_id = request.query_params.get("professor")
course_id = request.query_params.get("course") course_id = request.query_params.get("course")
@@ -291,19 +283,26 @@ class FileFilterView(APIView):
if semester_id: if semester_id:
queryset = queryset.filter(semester__id=semester_id) queryset = queryset.filter(semester__id=semester_id)
queryset = queryset.annotate(
upvote_count=Count("upvotes"), downvote_count=Count("downvotes")
).order_by(F("downvote_count") - F("upvote_count"))
# 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=timezone.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 # Loop through each serialized file to sort its peer_users
for file_data in serializer.data:
try:
serialized_data = serializer.data
print(serialized_data)
except Exception as e:
print(str(e))
for file_data in serialized_data:
print(file_data)
file_obj = File.objects.get(id=file_data["id"]) file_obj = File.objects.get(id=file_data["id"])
sorted_peer_users = sorted( sorted_peer_users = sorted(
file_obj.peer_users.all(), key=lambda x: x.points, reverse=True file_obj.peer_users.all(), key=lambda x: x.points, reverse=True
@@ -312,9 +311,72 @@ class FileFilterView(APIView):
sorted_peer_users, many=True sorted_peer_users, many=True
).data ).data
return Response(serializer.data) return Response(serialized_data)
except Exception as e: except Exception as e:
return Response( return Response(
{"error": f"Something went wrong: {str(e)}"}, {"error": f"Something went wrong: {str(e)}"},
status=status.HTTP_500_INTERNAL_SERVER_ERROR, status=status.HTTP_500_INTERNAL_SERVER_ERROR,
) )
class ReportUserView(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
def post(self, request):
data = request.data
update_user_ip(request)
try:
assert "file_id" in data
assert "user_id" in data
assert "description" in data
except AssertionError as e:
return Response(
{"error": f"Missing Parameters. {str(e)}"},
status=status.HTTP_400_BAD_REQUEST,
)
try:
file = File.objects.get(id=data["file_id"])
malicious_user = PeerUser.objects.get(id=data["user_id"])
reporting_user = request.user
description = data["description"]
except Exception as e:
return Response(
{"error": f"Missing/Incorrect Parameters. {str(e)}"},
status=status.HTTP_400_BAD_REQUEST,
)
existing_user_report_queryset = UserReport.objects.filter(
user=malicious_user, file=file, reporting_user=reporting_user
)
if len(existing_user_report_queryset):
existing_report = existing_user_report_queryset.first()
existing_report.description = description
existing_report.save()
return Response(
{
"msg": "User report already exists for this file. Updated description"
},
status=status.HTTP_208_ALREADY_REPORTED,
)
if (
file not in malicious_user.owned_files.all()
or file not in malicious_user.shared_files.all()
):
return Response(
{"error": "User does not own or host the file reported"},
status=status.HTTP_404_NOT_FOUND,
)
UserReport.objects.create(
user=malicious_user,
reporting_user=reporting_user,
file=file,
description=description,
)
malicious_user.points -= 1
malicious_user.save()
return Response({"msg": "Report Created!"}, status=status.HTTP_201_CREATED)