This commit is contained in:
AN 2025-01-14 14:04:31 +00:00 committed by GitHub
parent 19907b1e83
commit 2adf87af1d
11 changed files with 272 additions and 239 deletions

View file

@ -4,8 +4,8 @@ from .models import *
@admin.register(Course) @admin.register(Course)
class CourseAdmin(admin.ModelAdmin): class CourseAdmin(admin.ModelAdmin):
list_display = ('title', 'instructor', 'created_at', 'updated_at') list_display = ('title', 'owner', 'created_at', 'updated_at')
search_fields = ('title', 'instructor__username') search_fields = ('title', 'owner__username')
list_filter = ('created_at', 'updated_at') list_filter = ('created_at', 'updated_at')
@admin.register(Module) @admin.register(Module)

View file

@ -0,0 +1,18 @@
# Generated by Django 5.0.10 on 2025-01-14 08:17
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('app', '0004_course_rating'),
]
operations = [
migrations.RenameField(
model_name='course',
old_name='instructor',
new_name='owner',
),
]

View file

@ -0,0 +1,21 @@
# Generated by Django 5.0.10 on 2025-01-14 11:08
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0005_rename_instructor_course_owner'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='module',
name='created_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Created By'),
),
]

View file

@ -0,0 +1,21 @@
# Generated by Django 5.0.10 on 2025-01-14 11:10
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0006_module_created_by'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AlterField(
model_name='module',
name='created_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Created By'),
),
]

View file

@ -0,0 +1,21 @@
# Generated by Django 5.0.10 on 2025-01-14 12:12
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0007_alter_module_created_by'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='lesson',
name='created_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Created By'),
),
]

View file

@ -0,0 +1,23 @@
# Generated by Django 5.0.10 on 2025-01-14 13:02
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0008_lesson_created_by'),
]
operations = [
migrations.AddField(
model_name='lesson',
name='description',
field=models.TextField(null=True, verbose_name='Lesson Description'),
),
migrations.AlterField(
model_name='module',
name='description',
field=models.TextField(null=True, verbose_name='Module Description'),
),
]

View file

@ -13,7 +13,7 @@ class Course(models.Model):
image = models.ImageField(upload_to="courses/image", null=True) image = models.ImageField(upload_to="courses/image", null=True)
is_paid = models.BooleanField(default=False) is_paid = models.BooleanField(default=False)
price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True) price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
instructor = models.ForeignKey(User, on_delete=models.CASCADE, related_name='courses_taught', verbose_name="Instructor") owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='courses_taught', verbose_name="Instructor")
rating = models.PositiveSmallIntegerField(null=True, blank=True) rating = models.PositiveSmallIntegerField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Created At") created_at = models.DateTimeField(auto_now_add=True, verbose_name="Created At")
updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated At") updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated At")
@ -33,9 +33,10 @@ class Course(models.Model):
class Module(models.Model): class Module(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4, editable=False) id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
title = models.CharField(max_length=255, verbose_name="Module Title") title = models.CharField(max_length=255, verbose_name="Module Title")
description = models.TextField(verbose_name="Module Description") description = models.TextField(null=True, verbose_name="Module Description")
course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name='modules', verbose_name="Course") course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name='modules', verbose_name="Course")
order = models.PositiveIntegerField(default=0, verbose_name="Order", unique=True) order = models.PositiveIntegerField(default=0, verbose_name="Order", unique=True)
created_by = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, verbose_name="Created By")
def str(self): def str(self):
return self.title return self.title
@ -44,10 +45,12 @@ class Module(models.Model):
class Lesson(models.Model): class Lesson(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4, editable=False) id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
title = models.CharField(max_length=255, verbose_name="Lesson Title") title = models.CharField(max_length=255, verbose_name="Lesson Title")
description = models.TextField(null=True, verbose_name="Lesson Description")
content = models.TextField(verbose_name="Lesson Content") content = models.TextField(verbose_name="Lesson Content")
module = models.ForeignKey(Module, on_delete=models.CASCADE, related_name='lessons', verbose_name="Module") module = models.ForeignKey(Module, on_delete=models.CASCADE, related_name='lessons', verbose_name="Module")
order = models.PositiveIntegerField(default=0, verbose_name="Order") order = models.PositiveIntegerField(default=0, verbose_name="Order")
file = models.FileField(upload_to='lesson_files/', null=True, blank=True, verbose_name="Attached File") file = models.FileField(upload_to='lesson_files/', null=True, blank=True, verbose_name="Attached File")
created_by = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, verbose_name="Created By")
def str(self): def str(self):
return self.title return self.title

View file

@ -1,13 +1,32 @@
from rest_framework.permissions import BasePermission from rest_framework.permissions import IsAuthenticated, BasePermission, SAFE_METHODS
import logging
logger = logging.getLogger(__name__)
class IsOwnerOrReadOnly(BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in SAFE_METHODS:
return True
view_name = view.__class__.__name__
match view_name:
case "CourseViewSet":
return obj.owner == request.user
case "ModuleViewSet":
return obj.created_by == request.user
case "LessonViewSet":
return obj.created_by == request.user
class IsInstructor(BasePermission):
"""
Custom permission to allow access only to users with role 'instructor'.
"""
def has_permission(self, request, view):
# Ensure the user is authenticated and has a role of 'instructor'
return request.user.is_authenticated and request.user.role == 'instructor'
class IsAdmin(BasePermission): class IsAdmin(BasePermission):
""" """

View file

@ -11,36 +11,58 @@ from dj_rest_auth.registration.serializers import RegisterSerializer
class CourseSerializer(serializers.ModelSerializer): class CourseSerializer(serializers.ModelSerializer):
instructor_name = serializers.CharField(source='instructor.username', read_only=True) owner_name = serializers.CharField(source='owner.username', read_only=True)
class Meta: class Meta:
model = Course model = Course
fields = ['id', 'title', 'description', 'is_paid', 'price', 'image', 'instructor_name', 'created_at', 'updated_at'] fields = ['id', 'title', 'description', 'is_paid', 'price', 'image', 'owner_name', 'created_at', 'updated_at']
read_only_fields = ['created_at', 'updated_at'] read_only_fields = ['created_at', 'updated_at']
class ModuleSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Module
fields = ['url', 'id', 'title', 'description', 'course', 'order']
extra_kwargs = {
'url': {'view_name': 'modules-detail', 'lookup_field': 'id'}
}
class LessonSerializer(serializers.HyperlinkedModelSerializer): class LessonSerializer(serializers.ModelSerializer):
module = serializers.PrimaryKeyRelatedField(queryset=Module.objects.all()) module = serializers.PrimaryKeyRelatedField(queryset=Module.objects.all())
class Meta: class Meta:
model = Lesson model = Lesson
fields = ['url', 'id', 'title', 'content', 'module', 'order', 'file'] fields = ['id', 'title', 'description', 'content', 'module', 'order', 'file']
extra_kwargs = {
'url': {'view_name': 'lessons-detail', 'lookup_field': 'id'}
} class ModuleSerializer(serializers.ModelSerializer):
lessons = serializers.SerializerMethodField()
class Meta:
model = Module
fields = ['id', 'title', 'description', 'lessons', 'course', 'order']
read_only_fields = ['course', 'lessons']
def get_lessons(self, obj):
return obj.lessons.values('id', 'title', 'description')
class EnrollmentSerializer(serializers.ModelSerializer): class EnrollmentSerializer(serializers.ModelSerializer):
course_details = serializers.SerializerMethodField()
class Meta: class Meta:
model = Enrollment model = Enrollment
fields = ['id', 'student', 'course', 'enrolled_at', 'completed'] fields = ['id', 'course', 'course_details', 'enrolled_at', 'completed']
read_only_fields = ['enrolled_at']
def get_course_details(self, obj):
course = obj.course
request = self.context.get('request')
image_url = course.image.url if course.image else None
if image_url and request:
image_url = request.build_absolute_uri(image_url)
return {
"id": course.id,
"title": course.title,
"description": course.description,
"image": image_url,
"is_paid": course.is_paid,
"price": course.price,
"rating": course.rating,
}
class QuizSerializer(serializers.ModelSerializer): class QuizSerializer(serializers.ModelSerializer):

View file

@ -3,7 +3,6 @@ from .views import *
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
router = DefaultRouter() router = DefaultRouter()
router.register(r'courses-read', CourseRead, basename='course-read')
router.register(r'courses', CourseViewSet, basename='course') router.register(r'courses', CourseViewSet, basename='course')
router.register(r'modules', ModuleViewSet, basename='modules') router.register(r'modules', ModuleViewSet, basename='modules')
router.register(r'lessons', LessonViewSet, basename='lessons') router.register(r'lessons', LessonViewSet, basename='lessons')

View file

@ -5,69 +5,37 @@ from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework import status from rest_framework import status
from rest_framework.permissions import IsAuthenticated, BasePermission from rest_framework.permissions import IsAuthenticated, BasePermission
from .permissions import IsInstructor, IsAdmin from .permissions import IsOwnerOrReadOnly, IsAdmin
from rest_framework.decorators import action
from rest_framework.exceptions import PermissionDenied
class CourseRead(ReadOnlyModelViewSet):
permission_classes = [IsAuthenticated]
serializer_class = CourseSerializer
queryset = Course.objects.all()
class CourseViewSet(ModelViewSet): class CourseViewSet(ModelViewSet):
""" """
A ViewSet for viewing and editing Course instances. A ViewSet for viewing and editing Course instances.
""" """
permission_classes = [IsAuthenticated,] queryset = Course.objects.all()
permission_classes = [IsOwnerOrReadOnly]
serializer_class = CourseSerializer serializer_class = CourseSerializer
def get_queryset(self):
"""
Return courses belonging to the authenticated user.
"""
user = self.request.user
return Course.objects.filter(instructor=user)
def perform_create(self, serializer): def perform_create(self, serializer):
""" """
Save the post data when creating a new course. Save the post data when creating a new course.
""" """
user = self.request.user serializer.save(owner=self.request.user)
@action(detail=False, methods=['get'], url_path='my-courses', url_name='my_courses')
serializer.save(instructor=user) def get_my_course(self, request):
def perform_update(self, serializer):
""" """
Ensure that only the instructor can update their course. Custom GET method to fetch detailed information about my courses.
""" """
course = self.get_object()
if course.instructor != self.request.user:
return Response(
{"detail": "You do not have permission to edit this course."},
status=status.HTTP_403_FORBIDDEN,
)
serializer.save()
def perform_destroy(self, instance):
"""
Ensure that only the instructor can delete their course.
"""
if instance.instructor != self.request.user:
return Response(
{"detail": "You do not have permission to delete this course."},
status=status.HTTP_403_FORBIDDEN,
)
instance.delete()
my_courses = Course.objects.filter(owner=request.user)
# Serialize the data
serializer = self.get_serializer(my_courses, many=True)
return Response(serializer.data)
@ -77,15 +45,13 @@ class ModuleViewSet(ModelViewSet):
""" """
serializer_class = ModuleSerializer serializer_class = ModuleSerializer
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated, IsOwnerOrReadOnly]
lookup_field = 'id'
def get_queryset(self): def get_queryset(self):
""" """
Return modules only if the user is the course instructor. Return modules only if the user is the course owner.
""" """
course_id = self.request.query_params.get('course_id') course_id = self.request.query_params.get('pk')
if course_id: if course_id:
course = Course.objects.filter(id=course_id).first() course = Course.objects.filter(id=course_id).first()
if course: if course:
@ -95,39 +61,18 @@ class ModuleViewSet(ModelViewSet):
def perform_create(self, serializer): def perform_create(self, serializer):
""" """
Allow only the course instructor to create a module. Allow only the course owner to create a module.
""" """
course_id = self.request.data.get('course') course_id = self.request.data.get('course')
course = Course.objects.filter(id=course_id, instructor=self.request.user).first() course = Course.objects.filter(id=course_id, owner=self.request.user).first()
if not course: if not course:
return Response( return Response(
{"detail": "You do not have permission to delete this course."}, {"detail": "This course not found."},
status=status.HTTP_403_FORBIDDEN, status=status.HTTP_404_NOT_FOUND,
) )
serializer.save(course=course) serializer.save(course=course, created_by=self.request.user)
def perform_update(self, serializer):
"""
Allow only the course instructor to update the module.
"""
module = self.get_object()
if module.course.instructor != self.request.user:
return Response(
{"detail": "You do not have permission to delete this course."},
status=status.HTTP_403_FORBIDDEN,
)
serializer.save()
def perform_destroy(self, instance):
"""
Allow only the course instructor to delete the module.
"""
if instance.course.instructor != self.request.user:
return Response(
{"detail": "You do not have permission to delete this course."},
status=status.HTTP_403_FORBIDDEN,
)
instance.delete()
class LessonViewSet(ModelViewSet): class LessonViewSet(ModelViewSet):
""" """
@ -135,143 +80,83 @@ class LessonViewSet(ModelViewSet):
""" """
serializer_class = LessonSerializer serializer_class = LessonSerializer
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated, IsOwnerOrReadOnly]
lookup_field = 'id'
def get_queryset(self): def get_queryset(self):
""" """
Return lessons only if the user is authorized (instructor or student) and provides valid data. Return a specific lesson within a specific module only if the user is authorized.
""" """
# حالة جلب كائن واحد lesson_id = self.request.query_params.get('lesson_id') # Get lesson ID from the request
if self.kwargs.get(self.lookup_field): # 'id' by default module_id = self.request.query_params.get('module_id') # Get module ID from the request
lesson = Lesson.objects.filter(id=self.kwargs[self.lookup_field]).first()
if lesson:
course = lesson.module.course
# التحقق من الصلاحيات
if course.instructor == self.request.user or Enrollment.objects.filter(student=self.request.user, course=course).exists():
return Lesson.objects.filter(id=lesson.id)
return Lesson.objects.none()
# حالة جلب مجموعة بناءً على module_id # Check if both lesson_id and module_id are provided
module_id = self.request.query_params.get('module_id') if not lesson_id or not module_id:
if module_id: return Lesson.objects.none() # Return no results if either is missing
# Verify that the module exist
module = Module.objects.filter(id=module_id).first() module = Module.objects.filter(id=module_id).first()
if module:
course = module.course
# التحقق من الصلاحيات
if course.instructor == self.request.user or Enrollment.objects.filter(student=self.request.user, course=course).exists():
queryset = Lesson.objects.filter(module=module).order_by('order')
print(f"Queryset: {queryset}")
return queryset
# في حالة عدم وجود صلاحيات أو عدم تطابق البيانات
return Lesson.objects.none()
def perform_create(self, serializer):
"""
Allow only the course instructor to create a lesson within their module.
"""
module_id = self.request.data.get('module')
module = Module.objects.filter(id=module_id, course__instructor=self.request.user).first()
if not module: if not module:
return Response( return Lesson.objects.none() # Return no results if the module does not exist
{"detail": "You do not have permission to create a lesson in this module."},
status=status.HTTP_403_FORBIDDEN, # Verify that the lesson exists and is associated with the module
) lesson = Lesson.objects.filter(id=lesson_id, module=module).first()
serializer.save(module=module) if not lesson:
return Lesson.objects.none() # Return no results if the lesson does not exist or is not linked to the module
# Check if the user has access (owner of the course or enrolled in the course)
is_owner = module.course.owner == self.request.user
is_enrolled = Enrollment.objects.filter(course=module.course, student=self.request.user).exists()
if is_owner or is_enrolled:
return Lesson.objects.filter(id=lesson_id) # Return the lesson if the user is authorized
return Lesson.objects.none() # Deny access if the user is not authorized
def perform_update(self, serializer):
"""
Allow only the course instructor to update a lesson within their module.
"""
lesson = self.get_object()
if lesson.module.course.instructor != self.request.user:
return Response(
{"detail": "You do not have permission to update this lesson."},
status=status.HTTP_403_FORBIDDEN,
)
serializer.save()
def perform_destroy(self, instance):
"""
Allow only the course instructor to delete a lesson within their module.
"""
if instance.module.course.instructor != self.request.user:
return Response(
{"detail": "You do not have permission to delete this lesson."},
status=status.HTTP_403_FORBIDDEN,
)
instance.delete()
class EnrollmentViewSet(ModelViewSet): class EnrollmentViewSet(ModelViewSet):
queryset = Enrollment.objects.all() queryset = Enrollment.objects.all()
serializer_class = EnrollmentSerializer serializer_class = EnrollmentSerializer
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
http_method_names = ['get', 'post', 'delete']
def retrieve(self, request, *args, **kwargs):
instance = Enrollment.objects.filter(user=request.user)
serializer = self.get_serializer(instance)
return Response(serializer.data)
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
# Ensure the user is an instructor
if request.user.role != 'instructor':
return Response({"error": "Only instructors can enroll students"}, status=status.HTTP_403_FORBIDDEN)
# Get student and course data from the request
student_id = request.data.get('student_id')
course_id = request.data.get('course_id') course_id = request.data.get('course_id')
# Check if the student and course exist # Check if the student and course exist
try: try:
student = User.objects.get(id=student_id, role='student')
course = Course.objects.get(id=course_id) course = Course.objects.get(id=course_id)
except User.DoesNotExist:
return Response({"error": "Student not found"}, status=status.HTTP_404_NOT_FOUND)
except Course.DoesNotExist: except Course.DoesNotExist:
return Response({"error": "Course not found"}, status=status.HTTP_404_NOT_FOUND) return Response({"detail": "Course not found"}, status=status.HTTP_404_NOT_FOUND)
# Ensure the current instructor is the course instructor if Enrollment.objects.filter(student=request.user, course=course).exists():
if course.instructor != request.user: return Response({"detail": "You are already subscribed to this course."}, status=status.HTTP_404_NOT_FOUND)
return Response({"error": "You can only enroll students in your own courses"}, status=status.HTTP_403_FORBIDDEN) elif course.owner == request.user:
return Response({"detail": "You can't enroll in your course"}, status=status.HTTP_404_NOT_FOUND)
# Create a new enrollment # Create a new enrollment
enrollment = Enrollment.objects.create(student=student, course=course) enrollment = Enrollment.objects.create(student=request.user, course=course)
serializer = self.get_serializer(enrollment) serializer = self.get_serializer(enrollment)
return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.data, status=status.HTTP_201_CREATED)
def update(self, request, *args, **kwargs):
# Ensure the user is an instructor
if request.user.role != 'instructor':
return Response({"error": "Only instructors can update enrollments"}, status=status.HTTP_403_FORBIDDEN)
# Get the enrollment object to update
enrollment = self.get_object()
# Ensure the current instructor is the course instructor
if enrollment.course.instructor != request.user:
return Response({"error": "You can only update enrollments in your own courses"}, status=status.HTTP_403_FORBIDDEN)
# Update the enrollment
serializer = self.get_serializer(enrollment, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
def destroy(self, request, *args, **kwargs): def destroy(self, request, *args, **kwargs):
# Ensure the user is an instructor
if request.user.role != 'instructor':
return Response({"error": "Only instructors can delete enrollments"}, status=status.HTTP_403_FORBIDDEN)
# Get the enrollment object to delete # Get the enrollment object to delete
enrollment = self.get_object() enrollment = self.get_object()
if enrollment.student != request.user:
# Ensure the current instructor is the course instructor raise PermissionDenied("You do not have permission to delete this enrollment.")
if enrollment.course.instructor != request.user:
return Response({"error": "You can only delete enrollments in your own courses"}, status=status.HTTP_403_FORBIDDEN)
# Delete the enrollment # Delete the enrollment
enrollment.delete() enrollment.delete()
return Response({"message": "Enrollment deleted successfully"}, status=status.HTTP_204_NO_CONTENT) return Response({"detail": "Enrollment deleted successfully"}, status=status.HTTP_204_NO_CONTENT)
class QuizViewSet(ModelViewSet): class QuizViewSet(ModelViewSet):
queryset = Quiz.objects.all() queryset = Quiz.objects.all()
@ -279,19 +164,19 @@ class QuizViewSet(ModelViewSet):
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
# Ensure the user is an instructor # Ensure the user is an owner
if request.user.role != 'instructor': if request.user.role != 'owner':
return Response({"error": "Only instructors can create quizzes"}, status=status.HTTP_403_FORBIDDEN) return Response({"detail": "Only owners can create quizzes"}, status=status.HTTP_403_FORBIDDEN)
# Get course data from the request # Get course data from the request
moduleId = request.data.get('module') moduleId = request.data.get('module')
# Check if the course exists # Check if the course exists
try: try:
module = Module.objects.get(id=moduleId) module = Module.objects.get(id=moduleId)
except Course.DoesNotExist: except Course.DoesNotExist:
return Response({"error": "Course not found"}, status=status.HTTP_404_NOT_FOUND) return Response({"detail": "Course not found"}, status=status.HTTP_404_NOT_FOUND)
# Ensure the current instructor is the course instructor # Ensure the current owner is the course owner
if module.course.instructor != request.user: if module.course.owner != request.user:
return Response({"error": "You can only create quizzes for your own courses"}, status=status.HTTP_403_FORBIDDEN) return Response({"detail": "You can only create quizzes for your own courses"}, status=status.HTTP_403_FORBIDDEN)
# Create a new quiz # Create a new quiz
# data = request.data.copy() # نسخ البيانات لتجنب التعديل على الأصل # data = request.data.copy() # نسخ البيانات لتجنب التعديل على الأصل
# data.pop('module', None) # إزالة المفتاح module إذا كان موجودًا # data.pop('module', None) # إزالة المفتاح module إذا كان موجودًا
@ -301,14 +186,14 @@ class QuizViewSet(ModelViewSet):
def update(self, request, *args, **kwargs): def update(self, request, *args, **kwargs):
# Ensure the user is an instructor # Ensure the user is an owner
if request.user.role != 'instructor': if request.user.role != 'owner':
return Response({"error": "Only instructors can update quizzes"}, status=status.HTTP_403_FORBIDDEN) return Response({"detail": "Only owners can update quizzes"}, status=status.HTTP_403_FORBIDDEN)
# Get the quiz object to update # Get the quiz object to update
quiz = self.get_object() quiz = self.get_object()
# Ensure the current instructor is the course instructor # Ensure the current owner is the course owner
if quiz.module.course.instructor != request.user: if quiz.module.course.owner != request.user:
return Response({"error": "You can only update quizzes for your own courses"}, status=status.HTTP_403_FORBIDDEN) return Response({"detail": "You can only update quizzes for your own courses"}, status=status.HTTP_403_FORBIDDEN)
# Update the quiz # Update the quiz
serializer = self.get_serializer(quiz, data=request.data, partial=True) serializer = self.get_serializer(quiz, data=request.data, partial=True)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
@ -316,17 +201,17 @@ class QuizViewSet(ModelViewSet):
return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.data, status=status.HTTP_200_OK)
def destroy(self, request, *args, **kwargs): def destroy(self, request, *args, **kwargs):
# Ensure the user is an instructor # Ensure the user is an owner
if request.user.role != 'instructor': if request.user.role != 'owner':
return Response({"error": "Only instructors can delete quizzes"}, status=status.HTTP_403_FORBIDDEN) return Response({"detail": "Only owners can delete quizzes"}, status=status.HTTP_403_FORBIDDEN)
# Get the quiz object to delete # Get the quiz object to delete
quiz = self.get_object() quiz = self.get_object()
# Ensure the current instructor is the course instructor # Ensure the current owner is the course owner
if quiz.module.course.instructor != request.user: if quiz.module.course.owner != request.user:
return Response({"error": "You can only delete quizzes for your own courses"}, status=status.HTTP_403_FORBIDDEN) return Response({"detail": "You can only delete quizzes for your own courses"}, status=status.HTTP_403_FORBIDDEN)
# Delete the quiz # Delete the quiz
quiz.delete() quiz.delete()
return Response({"message": "Quiz deleted successfully"}, status=status.HTTP_204_NO_CONTENT) return Response({"detail": "Quiz deleted successfully"}, status=status.HTTP_204_NO_CONTENT)
class CertificateViewSet(ModelViewSet): class CertificateViewSet(ModelViewSet):
@ -336,7 +221,8 @@ class CertificateViewSet(ModelViewSet):
def get_permissions(self): def get_permissions(self):
if self.action == 'create': if self.action == 'create':
permission_classes = [IsInstructor] # permission_classes = [Isowner]
pass
elif self.action in ['update', 'destroy']: elif self.action in ['update', 'destroy']:
permission_classes = [IsAdmin] permission_classes = [IsAdmin]
else: else:
@ -354,12 +240,12 @@ class CertificateViewSet(ModelViewSet):
course = Course.objects.get(id=courseId) course = Course.objects.get(id=courseId)
student = User.objects.get(id=student_id, role='student') student = User.objects.get(id=student_id, role='student')
except User.DoesNotExist: except User.DoesNotExist:
return Response({"error": "Student not found"}, status=status.HTTP_404_NOT_FOUND) return Response({"detail": "Student not found"}, status=status.HTTP_404_NOT_FOUND)
except Course.DoesNotExist: except Course.DoesNotExist:
return Response({"error": "Course not found"}, status=status.HTTP_404_NOT_FOUND) return Response({"detail": "Course not found"}, status=status.HTTP_404_NOT_FOUND)
# Ensure the current instructor is the course instructor # Ensure the current owner is the course owner
if course.instructor != request.user: if course.owner != request.user:
return Response({"error": "You can only create certificate for your own courses"}, status=status.HTTP_403_FORBIDDEN) return Response({"detail": "You can only create certificate for your own courses"}, status=status.HTTP_403_FORBIDDEN)
certificate = Certificate.objects.create(course=course, student=student) certificate = Certificate.objects.create(course=course, student=student)
serializer = self.get_serializer(certificate) serializer = self.get_serializer(certificate)