mirror of
https://github.com/AmanTahiliani/PeerNotes.git
synced 2026-08-07 19:56:19 -04:00
Merge pull request #6 from AmanTahiliani/feature-aman-filter-addition
Filters, File registration and README
This commit is contained in:
67
backend/README.md
Normal file
67
backend/README.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# Django Backend
|
||||||
|
|
||||||
|
This is the backend for the Django project.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
1. Create a virtual environment:
|
||||||
|
```bash
|
||||||
|
python3 -m venv venv
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Activate the virtual environment:
|
||||||
|
- For macOS/Linux:
|
||||||
|
```bash
|
||||||
|
source venv/bin/activate
|
||||||
|
```
|
||||||
|
- For Windows:
|
||||||
|
```bash
|
||||||
|
venv\Scripts\activate
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Install the project dependencies:
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running the Server
|
||||||
|
|
||||||
|
To start the Django server, run the following command:
|
||||||
|
```bash
|
||||||
|
python3 manage.py runserver
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, the server will run on `http://localhost:8000/`.
|
||||||
|
|
||||||
|
## Admin Panel
|
||||||
|
In order to access the admin panel, you need to create a superuser. To do this, run the following command:
|
||||||
|
```bash
|
||||||
|
python3 manage.py createsuperuser
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, you can access the admin panel by visiting `http://localhost:8000/admin/` and logging in with the superuser credentials.
|
||||||
|
|
||||||
|
## Contributing to the Codebase
|
||||||
|
1. Create a new branch:
|
||||||
|
```bash
|
||||||
|
git checkout -b <branch-name>
|
||||||
|
```
|
||||||
|
2. Make your changes.
|
||||||
|
|
||||||
|
3. Use black to format your code:
|
||||||
|
```bash
|
||||||
|
black .
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Make your changes and commit them:
|
||||||
|
```bash
|
||||||
|
git add .
|
||||||
|
git commit -m "Your commit message"
|
||||||
|
```
|
||||||
|
5. Push your changes to the remote repository:
|
||||||
|
```bash
|
||||||
|
git push origin <branch-name>
|
||||||
|
```
|
||||||
|
6. Create a Pull Request on GitHub.
|
||||||
|
|
||||||
|
|
||||||
@@ -1,5 +1,10 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from api.models import PeerUser
|
from api.models import PeerUser, Semester, Professor, Course, Topic, File
|
||||||
|
|
||||||
# Register your models here.
|
# Register your models here.
|
||||||
admin.site.register(PeerUser)
|
admin.site.register(PeerUser)
|
||||||
|
admin.site.register(Topic)
|
||||||
|
admin.site.register(Professor)
|
||||||
|
admin.site.register(Course)
|
||||||
|
admin.site.register(File)
|
||||||
|
admin.site.register(Semester)
|
||||||
|
|||||||
@@ -0,0 +1,138 @@
|
|||||||
|
# Generated by Django 4.2.11 on 2024-03-26 04:40
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("api", "0001_initial"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Course",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.CharField(max_length=20)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Professor",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.CharField(max_length=100)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Semester",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.CharField(max_length=20)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Topic",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.CharField(max_length=100)),
|
||||||
|
("description", models.TextField(blank=True)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="peeruser",
|
||||||
|
name="last_poll",
|
||||||
|
field=models.DateTimeField(
|
||||||
|
auto_now_add=True, default=django.utils.timezone.now
|
||||||
|
),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="File",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("filename", models.CharField(max_length=200)),
|
||||||
|
(
|
||||||
|
"original_author",
|
||||||
|
models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"peer_users",
|
||||||
|
models.ManyToManyField(
|
||||||
|
related_name="shared_files", to=settings.AUTH_USER_MODEL
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"professor",
|
||||||
|
models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
to="api.professor",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"semester",
|
||||||
|
models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
to="api.semester",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"topic",
|
||||||
|
models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
to="api.topic",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# Generated by Django 4.2.11 on 2024-03-26 16:30
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("api", "0002_course_professor_semester_topic_peeruser_last_poll_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="file",
|
||||||
|
name="course",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="files",
|
||||||
|
to="api.course",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="file",
|
||||||
|
name="original_author",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="owned_files",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="file",
|
||||||
|
name="professor",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="files",
|
||||||
|
to="api.professor",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="file",
|
||||||
|
name="semester",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="files",
|
||||||
|
to="api.semester",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="file",
|
||||||
|
name="topic",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="files",
|
||||||
|
to="api.topic",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Generated by Django 4.2.11 on 2024-03-26 17:52
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("api", "0003_file_course_alter_file_original_author_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="course",
|
||||||
|
name="number",
|
||||||
|
field=models.CharField(
|
||||||
|
default=django.utils.timezone.now, max_length=20, unique=True
|
||||||
|
),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="course",
|
||||||
|
name="name",
|
||||||
|
field=models.CharField(blank=True, max_length=40),
|
||||||
|
),
|
||||||
|
]
|
||||||
22
backend/api/migrations/0005_file_created_at.py
Normal file
22
backend/api/migrations/0005_file_created_at.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Generated by Django 4.2.11 on 2024-03-26 23:14
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("api", "0004_course_number_alter_course_name"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="file",
|
||||||
|
name="created_at",
|
||||||
|
field=models.DateTimeField(
|
||||||
|
auto_now_add=True, default=django.utils.timezone.now
|
||||||
|
),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -5,3 +5,58 @@ 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)
|
||||||
|
|
||||||
|
|
||||||
|
class Topic(models.Model):
|
||||||
|
name = models.CharField(max_length=100, blank=False, null=False)
|
||||||
|
description = models.TextField(blank=True)
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
class Professor(models.Model):
|
||||||
|
name = models.CharField(max_length=100, blank=False, null=False)
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
class Semester(models.Model):
|
||||||
|
name = models.CharField(max_length=20, blank=False, null=False)
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
class Course(models.Model):
|
||||||
|
name = models.CharField(max_length=40, blank=True)
|
||||||
|
number = models.CharField(max_length=20, blank=False, null=False, unique=True)
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.number + f" ({self.name})"
|
||||||
|
|
||||||
|
|
||||||
|
class File(models.Model):
|
||||||
|
filename = models.CharField(max_length=200, blank=False, null=False)
|
||||||
|
original_author = models.ForeignKey(
|
||||||
|
PeerUser, on_delete=models.SET_NULL, null=True, related_name="owned_files"
|
||||||
|
)
|
||||||
|
peer_users = models.ManyToManyField(PeerUser, related_name="shared_files")
|
||||||
|
topic = models.ForeignKey(
|
||||||
|
Topic, on_delete=models.SET_NULL, null=True, related_name="files"
|
||||||
|
)
|
||||||
|
professor = models.ForeignKey(
|
||||||
|
Professor, on_delete=models.SET_NULL, null=True, related_name="files"
|
||||||
|
)
|
||||||
|
semester = models.ForeignKey(
|
||||||
|
Semester, on_delete=models.SET_NULL, null=True, related_name="files"
|
||||||
|
)
|
||||||
|
course = models.ForeignKey(
|
||||||
|
Course, on_delete=models.SET_NULL, null=True, related_name="files"
|
||||||
|
)
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.filename
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from .models import PeerUser
|
from .models import PeerUser, Topic, Semester, Professor, Course, File
|
||||||
|
|
||||||
|
|
||||||
class LoginSerializer(serializers.Serializer):
|
class LoginSerializer(serializers.Serializer):
|
||||||
@@ -11,3 +11,39 @@ class UserSerializer(serializers.ModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = PeerUser
|
model = PeerUser
|
||||||
fields = ["id", "username", "email", "ip_address"]
|
fields = ["id", "username", "email", "ip_address"]
|
||||||
|
|
||||||
|
|
||||||
|
class TopicSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Topic
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
|
class ProfessorSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Professor
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
|
class SemesterSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Semester
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
|
class CourseSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Course
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
|
class FileSerializer(serializers.ModelSerializer):
|
||||||
|
original_author = UserSerializer()
|
||||||
|
peer_users = UserSerializer(many=True)
|
||||||
|
topic = TopicSerializer()
|
||||||
|
professor = ProfessorSerializer()
|
||||||
|
semester = SemesterSerializer()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = File
|
||||||
|
fields = "__all__"
|
||||||
|
|||||||
@@ -16,9 +16,45 @@ Including another URLconf
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from api.user_login import LoginView, SignupView
|
from api.user_login import LoginView, SignupView, PollOnlineView
|
||||||
|
from api import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("api/login/", LoginView.as_view(), name="login"),
|
path("api/login/", LoginView.as_view(), name="login"),
|
||||||
path("api/signup/", SignupView.as_view(), name="signup"),
|
path("api/signup/", SignupView.as_view(), name="signup"),
|
||||||
|
path("api/poll/", PollOnlineView.as_view(), name="poll"),
|
||||||
|
path("api/topics/", views.TopicListCreateAPIView.as_view(), name="topic-list"),
|
||||||
|
path(
|
||||||
|
"api/topics/<int:pk>/", views.TopicDetailAPIView.as_view(), name="topic-detail"
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"api/professors/",
|
||||||
|
views.ProfessorListCreateAPIView.as_view(),
|
||||||
|
name="professor-list",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"api/professors/<int:pk>/",
|
||||||
|
views.ProfessorDetailAPIView.as_view(),
|
||||||
|
name="professor-detail",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"api/semesters/",
|
||||||
|
views.SemesterListCreateAPIView.as_view(),
|
||||||
|
name="semester-list",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"api/semesters/<int:pk>/",
|
||||||
|
views.SemesterDetailAPIView.as_view(),
|
||||||
|
name="semester-detail",
|
||||||
|
),
|
||||||
|
path("api/courses/", views.CourseListCreateAPIView.as_view(), name="course-list"),
|
||||||
|
path(
|
||||||
|
"api/courses/<int:pk>/",
|
||||||
|
views.CourseDetailAPIView.as_view(),
|
||||||
|
name="course-detail",
|
||||||
|
),
|
||||||
|
path("api/files/", views.FileListCreateAPIView.as_view(), name="file-list"),
|
||||||
|
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"),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -4,15 +4,9 @@ from rest_framework import status
|
|||||||
from rest_framework.authtoken.models import Token
|
from rest_framework.authtoken.models import Token
|
||||||
from rest_framework.response import Response
|
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.permissions import IsAuthenticated
|
||||||
def get_client_ip(request):
|
from api.utils.get_client_ip import get_client_ip
|
||||||
x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
|
|
||||||
if x_forwarded_for:
|
|
||||||
ip = x_forwarded_for.split(",")[0]
|
|
||||||
else:
|
|
||||||
ip = request.META.get("REMOTE_ADDR")
|
|
||||||
return ip
|
|
||||||
|
|
||||||
|
|
||||||
class LoginView(APIView):
|
class LoginView(APIView):
|
||||||
@@ -59,3 +53,24 @@ class SignupView(APIView):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
|
class PollOnlineView(APIView):
|
||||||
|
authentication_classes = [TokenAuthentication]
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
try:
|
||||||
|
user = request.user
|
||||||
|
ip_address = get_client_ip(request)
|
||||||
|
user.ip_address = ip_address
|
||||||
|
user.save()
|
||||||
|
return Response(
|
||||||
|
{
|
||||||
|
"Message": "IP address updated successfully",
|
||||||
|
"username": user.username,
|
||||||
|
},
|
||||||
|
status=status.HTTP_200_OK,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|||||||
0
backend/api/utils/__init__.py
Normal file
0
backend/api/utils/__init__.py
Normal file
14
backend/api/utils/get_client_ip.py
Normal file
14
backend/api/utils/get_client_ip.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
def get_client_ip(request):
|
||||||
|
x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
|
||||||
|
if x_forwarded_for:
|
||||||
|
ip = x_forwarded_for.split(",")[0]
|
||||||
|
else:
|
||||||
|
ip = request.META.get("REMOTE_ADDR")
|
||||||
|
return ip
|
||||||
|
|
||||||
|
|
||||||
|
def update_user_ip(request):
|
||||||
|
user = request.user
|
||||||
|
ip_address = get_client_ip(request)
|
||||||
|
user.ip_address = ip_address
|
||||||
|
user.save()
|
||||||
@@ -1,6 +1,240 @@
|
|||||||
from rest_framework.views import APIView
|
from api.models import Course, File, Professor, Semester, Topic, PeerUser
|
||||||
from rest_framework.response import Response
|
from api.serializers import (
|
||||||
from api.serializers import LoginSerializer
|
CourseSerializer,
|
||||||
|
FileSerializer,
|
||||||
|
ProfessorSerializer,
|
||||||
|
SemesterSerializer,
|
||||||
|
TopicSerializer,
|
||||||
|
)
|
||||||
|
from datetime import datetime, timedelta
|
||||||
from django.contrib.auth import authenticate
|
from django.contrib.auth import authenticate
|
||||||
|
from django.db import transaction
|
||||||
|
from rest_framework import generics, status
|
||||||
|
from rest_framework.authentication import TokenAuthentication
|
||||||
from rest_framework.authtoken.models import Token
|
from rest_framework.authtoken.models import Token
|
||||||
from rest_framework import status
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
from rest_framework import filters
|
||||||
|
from rest_framework.exceptions import ValidationError, NotFound
|
||||||
|
from api.utils.get_client_ip import update_user_ip
|
||||||
|
|
||||||
|
|
||||||
|
class TopicListCreateAPIView(generics.ListCreateAPIView):
|
||||||
|
queryset = Topic.objects.all()
|
||||||
|
serializer_class = TopicSerializer
|
||||||
|
authentication_classes = [TokenAuthentication]
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
filter_backends = [filters.SearchFilter]
|
||||||
|
search_fields = ["name"]
|
||||||
|
|
||||||
|
|
||||||
|
class TopicDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
|
queryset = Topic.objects.all()
|
||||||
|
serializer_class = TopicSerializer
|
||||||
|
authentication_classes = [TokenAuthentication]
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
|
||||||
|
class ProfessorListCreateAPIView(generics.ListCreateAPIView):
|
||||||
|
queryset = Professor.objects.all()
|
||||||
|
serializer_class = ProfessorSerializer
|
||||||
|
authentication_classes = [TokenAuthentication]
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
filter_backends = [filters.SearchFilter]
|
||||||
|
search_fields = ["name"]
|
||||||
|
|
||||||
|
|
||||||
|
class ProfessorDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
|
queryset = Professor.objects.all()
|
||||||
|
serializer_class = ProfessorSerializer
|
||||||
|
authentication_classes = [TokenAuthentication]
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
|
||||||
|
class SemesterListCreateAPIView(generics.ListCreateAPIView):
|
||||||
|
queryset = Semester.objects.all()
|
||||||
|
serializer_class = SemesterSerializer
|
||||||
|
authentication_classes = [TokenAuthentication]
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
filter_backends = [filters.SearchFilter]
|
||||||
|
search_fields = ["name"]
|
||||||
|
|
||||||
|
|
||||||
|
class SemesterDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
|
queryset = Semester.objects.all()
|
||||||
|
serializer_class = SemesterSerializer
|
||||||
|
authentication_classes = [TokenAuthentication]
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
def delete(self, request, *args, **kwargs):
|
||||||
|
instance = self.get_object()
|
||||||
|
self.perform_destroy(instance)
|
||||||
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
|
|
||||||
|
class CourseListCreateAPIView(generics.ListCreateAPIView):
|
||||||
|
queryset = Course.objects.all()
|
||||||
|
serializer_class = CourseSerializer
|
||||||
|
authentication_classes = [TokenAuthentication]
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
filter_backends = [filters.SearchFilter]
|
||||||
|
search_fields = ["name"]
|
||||||
|
|
||||||
|
|
||||||
|
class CourseDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
|
queryset = Course.objects.all()
|
||||||
|
serializer_class = CourseSerializer
|
||||||
|
authentication_classes = [TokenAuthentication]
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
|
||||||
|
class FileListCreateAPIView(generics.ListCreateAPIView):
|
||||||
|
queryset = File.objects.all()
|
||||||
|
serializer_class = FileSerializer
|
||||||
|
authentication_classes = [TokenAuthentication]
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
filter_backends = [filters.SearchFilter]
|
||||||
|
search_fields = ["name"]
|
||||||
|
|
||||||
|
|
||||||
|
class FileDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
|
queryset = File.objects.all()
|
||||||
|
serializer_class = FileSerializer
|
||||||
|
authentication_classes = [TokenAuthentication]
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
|
||||||
|
class RegisterFile(APIView):
|
||||||
|
authentication_classes = [TokenAuthentication]
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
user = request.user
|
||||||
|
update_user_ip(request)
|
||||||
|
data = request.data
|
||||||
|
try:
|
||||||
|
with transaction.atomic():
|
||||||
|
required_fields = set(
|
||||||
|
["filename", "topic", "semester", "professor", "course"]
|
||||||
|
)
|
||||||
|
provided_fields = set(request.data.keys())
|
||||||
|
missing_fields = required_fields - provided_fields
|
||||||
|
|
||||||
|
if any(["filename", "topic"]) in missing_fields:
|
||||||
|
raise ValidationError(
|
||||||
|
"Missing one or more of the required field(s): filename, topic"
|
||||||
|
)
|
||||||
|
|
||||||
|
file = File.objects.create(
|
||||||
|
filename=data["filename"], original_author=user
|
||||||
|
)
|
||||||
|
file.peer_users.add(user)
|
||||||
|
|
||||||
|
file.course = (
|
||||||
|
Course.objects.get(id=data.get("course"))
|
||||||
|
if data.get("course")
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
file.professor = (
|
||||||
|
Professor.objects.get(id=data.get("professor"))
|
||||||
|
if data.get("professor")
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
file.semester = (
|
||||||
|
Semester.objects.get(id=data.get("semester"))
|
||||||
|
if data.get("semester")
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
|
topic_id = data["topic"]
|
||||||
|
|
||||||
|
try:
|
||||||
|
topic = Topic.objects.get(id=topic_id)
|
||||||
|
file.topic = topic
|
||||||
|
except Exception as e:
|
||||||
|
topic_serializer = TopicSerializer(data=topic_id)
|
||||||
|
if topic_serializer.is_valid():
|
||||||
|
topic = topic_serializer.save()
|
||||||
|
file.topic = topic
|
||||||
|
|
||||||
|
response_data = {
|
||||||
|
"id": file.id,
|
||||||
|
"filename": file.filename,
|
||||||
|
"topic": file.topic.name if file.topic else None,
|
||||||
|
"semester": file.semester.name if file.semester else None,
|
||||||
|
"course": file.course.name if file.course else None,
|
||||||
|
"professor": file.professor.name if file.professor else None,
|
||||||
|
}
|
||||||
|
file.save()
|
||||||
|
return Response(
|
||||||
|
response_data,
|
||||||
|
status=status.HTTP_201_CREATED,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
print("Error", str(e))
|
||||||
|
return Response(
|
||||||
|
{"error(s)": "Something went wrong"}, status=status.HTTP_400_BAD_REQUEST
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FileFilterView(APIView):
|
||||||
|
authentication_classes = [TokenAuthentication]
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
def get(self, request, format=None):
|
||||||
|
try:
|
||||||
|
# Extract filters from the query parameters
|
||||||
|
topic_id = request.query_params.get("topic")
|
||||||
|
professor_id = request.query_params.get("professor")
|
||||||
|
course_id = request.query_params.get("course")
|
||||||
|
semester_id = request.query_params.get("semester")
|
||||||
|
|
||||||
|
# Check if provided filter IDs exist
|
||||||
|
if topic_id and not Topic.objects.filter(id=topic_id).exists():
|
||||||
|
return Response(
|
||||||
|
{"error": f"Topic with id {topic_id} does not exist"},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
||||||
|
if professor_id and not Professor.objects.filter(id=professor_id).exists():
|
||||||
|
return Response(
|
||||||
|
{"error": f"Professor with id {professor_id} does not exist"},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
||||||
|
if course_id and not Course.objects.filter(id=course_id).exists():
|
||||||
|
return Response(
|
||||||
|
{"error": f"Course with id {course_id} does not exist"},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
||||||
|
if semester_id and not Semester.objects.filter(id=semester_id).exists():
|
||||||
|
return Response(
|
||||||
|
{"error": f"Semester with id {semester_id} does not exist"},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Start with the base queryset
|
||||||
|
queryset = File.objects.all()
|
||||||
|
|
||||||
|
# Apply filters if they are provided
|
||||||
|
if topic_id:
|
||||||
|
queryset = queryset.filter(topic__id=topic_id)
|
||||||
|
if professor_id:
|
||||||
|
queryset = queryset.filter(professor__id=professor_id)
|
||||||
|
if course_id:
|
||||||
|
queryset = queryset.filter(course__id=course_id)
|
||||||
|
if semester_id:
|
||||||
|
queryset = queryset.filter(semester__id=semester_id)
|
||||||
|
|
||||||
|
# Filter files based on active peers in the past hour
|
||||||
|
active_peer_ids = PeerUser.objects.filter(
|
||||||
|
last_poll__gte=datetime.now() - timedelta(hours=1)
|
||||||
|
).values_list("id", flat=True)
|
||||||
|
|
||||||
|
queryset = queryset.filter(peer_users__in=active_peer_ids).distinct()
|
||||||
|
|
||||||
|
serializer = FileSerializer(queryset, many=True)
|
||||||
|
return Response(serializer.data)
|
||||||
|
except Exception as e:
|
||||||
|
return Response(
|
||||||
|
{"error": f"Something went wrong: {str(e)}"},
|
||||||
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
)
|
||||||
|
|||||||
0
backend/api/views/filters.py
Normal file
0
backend/api/views/filters.py
Normal file
@@ -25,7 +25,7 @@ SECRET_KEY = "django-insecure-rh0s*u8$uugtt10cxbifjriaz%@&p1w!)c2=y^undd2*nx5
|
|||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
|
|
||||||
ALLOWED_HOSTS = []
|
ALLOWED_HOSTS = ["10.20.4.109", "73.7.29.136", "localhost"]
|
||||||
|
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|||||||
Reference in New Issue
Block a user