From 11c20c04742173bdb683bc4857934a1344eb40d9 Mon Sep 17 00:00:00 2001 From: AN Date: Tue, 14 Jan 2025 14:04:31 +0000 Subject: [PATCH] u --- lms/app/admin.py | 4 +- .../0005_rename_instructor_course_owner.py | 18 + lms/app/migrations/0006_module_created_by.py | 21 ++ .../0007_alter_module_created_by.py | 21 ++ lms/app/migrations/0008_lesson_created_by.py | 21 ++ ...on_description_alter_module_description.py | 23 ++ lms/app/models.py | 7 +- lms/app/permissions.py | 35 +- lms/app/serializers.py | 52 ++- lms/app/urls.py | 1 - lms/app/views.py | 308 ++++++------------ 11 files changed, 272 insertions(+), 239 deletions(-) create mode 100644 lms/app/migrations/0005_rename_instructor_course_owner.py create mode 100644 lms/app/migrations/0006_module_created_by.py create mode 100644 lms/app/migrations/0007_alter_module_created_by.py create mode 100644 lms/app/migrations/0008_lesson_created_by.py create mode 100644 lms/app/migrations/0009_lesson_description_alter_module_description.py diff --git a/lms/app/admin.py b/lms/app/admin.py index 6c4d41e..d600a86 100644 --- a/lms/app/admin.py +++ b/lms/app/admin.py @@ -4,8 +4,8 @@ from .models import * @admin.register(Course) class CourseAdmin(admin.ModelAdmin): - list_display = ('title', 'instructor', 'created_at', 'updated_at') - search_fields = ('title', 'instructor__username') + list_display = ('title', 'owner', 'created_at', 'updated_at') + search_fields = ('title', 'owner__username') list_filter = ('created_at', 'updated_at') @admin.register(Module) diff --git a/lms/app/migrations/0005_rename_instructor_course_owner.py b/lms/app/migrations/0005_rename_instructor_course_owner.py new file mode 100644 index 0000000..85157b9 --- /dev/null +++ b/lms/app/migrations/0005_rename_instructor_course_owner.py @@ -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', + ), + ] diff --git a/lms/app/migrations/0006_module_created_by.py b/lms/app/migrations/0006_module_created_by.py new file mode 100644 index 0000000..898a84f --- /dev/null +++ b/lms/app/migrations/0006_module_created_by.py @@ -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'), + ), + ] diff --git a/lms/app/migrations/0007_alter_module_created_by.py b/lms/app/migrations/0007_alter_module_created_by.py new file mode 100644 index 0000000..c4c4e73 --- /dev/null +++ b/lms/app/migrations/0007_alter_module_created_by.py @@ -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'), + ), + ] diff --git a/lms/app/migrations/0008_lesson_created_by.py b/lms/app/migrations/0008_lesson_created_by.py new file mode 100644 index 0000000..d075675 --- /dev/null +++ b/lms/app/migrations/0008_lesson_created_by.py @@ -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'), + ), + ] diff --git a/lms/app/migrations/0009_lesson_description_alter_module_description.py b/lms/app/migrations/0009_lesson_description_alter_module_description.py new file mode 100644 index 0000000..d54cac7 --- /dev/null +++ b/lms/app/migrations/0009_lesson_description_alter_module_description.py @@ -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'), + ), + ] diff --git a/lms/app/models.py b/lms/app/models.py index 3c71f51..6bae408 100644 --- a/lms/app/models.py +++ b/lms/app/models.py @@ -13,7 +13,7 @@ class Course(models.Model): image = models.ImageField(upload_to="courses/image", null=True) is_paid = models.BooleanField(default=False) 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) created_at = models.DateTimeField(auto_now_add=True, verbose_name="Created At") updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated At") @@ -33,9 +33,10 @@ class Course(models.Model): class Module(models.Model): id = models.UUIDField(primary_key=True, default=uuid4, editable=False) 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") 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): return self.title @@ -44,10 +45,12 @@ class Module(models.Model): class Lesson(models.Model): id = models.UUIDField(primary_key=True, default=uuid4, editable=False) 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") module = models.ForeignKey(Module, on_delete=models.CASCADE, related_name='lessons', verbose_name="Module") order = models.PositiveIntegerField(default=0, verbose_name="Order") 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): return self.title diff --git a/lms/app/permissions.py b/lms/app/permissions.py index 2f0f87c..3466866 100644 --- a/lms/app/permissions.py +++ b/lms/app/permissions.py @@ -1,14 +1,33 @@ -from rest_framework.permissions import BasePermission +from rest_framework.permissions import IsAuthenticated, BasePermission, SAFE_METHODS +import logging -class IsInstructor(BasePermission): - """ - Custom permission to allow access only to users with role 'instructor'. - """ +logger = logging.getLogger(__name__) - 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 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 IsAdmin(BasePermission): """ Custom permission to allow access only to users with role 'instructor'. diff --git a/lms/app/serializers.py b/lms/app/serializers.py index cb6c755..84e5923 100644 --- a/lms/app/serializers.py +++ b/lms/app/serializers.py @@ -11,36 +11,58 @@ from dj_rest_auth.registration.serializers import RegisterSerializer 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: 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'] -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()) class Meta: model = Lesson - fields = ['url', 'id', 'title', 'content', 'module', 'order', 'file'] - extra_kwargs = { - 'url': {'view_name': 'lessons-detail', 'lookup_field': 'id'} - } + fields = ['id', 'title', 'description', 'content', 'module', 'order', 'file'] + + +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): + course_details = serializers.SerializerMethodField() class Meta: 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): diff --git a/lms/app/urls.py b/lms/app/urls.py index 0da36a6..7da3919 100644 --- a/lms/app/urls.py +++ b/lms/app/urls.py @@ -3,7 +3,6 @@ from .views import * from rest_framework.routers import DefaultRouter router = DefaultRouter() -router.register(r'courses-read', CourseRead, basename='course-read') router.register(r'courses', CourseViewSet, basename='course') router.register(r'modules', ModuleViewSet, basename='modules') router.register(r'lessons', LessonViewSet, basename='lessons') diff --git a/lms/app/views.py b/lms/app/views.py index a49c92d..9bb8ca7 100644 --- a/lms/app/views.py +++ b/lms/app/views.py @@ -5,69 +5,37 @@ from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet from rest_framework.response import Response from rest_framework import status from rest_framework.permissions import IsAuthenticated, BasePermission -from .permissions import IsInstructor, IsAdmin - - - - -class CourseRead(ReadOnlyModelViewSet): - permission_classes = [IsAuthenticated] - serializer_class = CourseSerializer - queryset = Course.objects.all() - +from .permissions import IsOwnerOrReadOnly, IsAdmin +from rest_framework.decorators import action +from rest_framework.exceptions import PermissionDenied class CourseViewSet(ModelViewSet): """ A ViewSet for viewing and editing Course instances. """ - permission_classes = [IsAuthenticated,] + queryset = Course.objects.all() + permission_classes = [IsOwnerOrReadOnly] 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): """ Save the post data when creating a new course. """ - user = self.request.user - - - serializer.save(instructor=user) - - def perform_update(self, serializer): + serializer.save(owner=self.request.user) + + @action(detail=False, methods=['get'], url_path='my-courses', url_name='my_courses') + def get_my_course(self, request): """ - 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 - permission_classes = [IsAuthenticated] - lookup_field = 'id' - + permission_classes = [IsAuthenticated, IsOwnerOrReadOnly] 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: course = Course.objects.filter(id=course_id).first() if course: @@ -95,39 +61,18 @@ class ModuleViewSet(ModelViewSet): 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 = 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: return Response( - {"detail": "You do not have permission to delete this course."}, - status=status.HTTP_403_FORBIDDEN, + {"detail": "This course not found."}, + 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): """ @@ -135,143 +80,83 @@ class LessonViewSet(ModelViewSet): """ serializer_class = LessonSerializer - permission_classes = [IsAuthenticated] - lookup_field = 'id' - + permission_classes = [IsAuthenticated, IsOwnerOrReadOnly] 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. """ - # حالة جلب كائن واحد - if self.kwargs.get(self.lookup_field): # 'id' by default - 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() + lesson_id = self.request.query_params.get('lesson_id') # Get lesson ID from the request + module_id = self.request.query_params.get('module_id') # Get module ID from the request - # حالة جلب مجموعة بناءً على module_id - module_id = self.request.query_params.get('module_id') - if module_id: - 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 + # Check if both lesson_id and module_id are provided + if not lesson_id or not module_id: + return Lesson.objects.none() # Return no results if either is missing - # في حالة عدم وجود صلاحيات أو عدم تطابق البيانات - 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() + # Verify that the module exist + module = Module.objects.filter(id=module_id).first() if not module: - return Response( - {"detail": "You do not have permission to create a lesson in this module."}, - status=status.HTTP_403_FORBIDDEN, - ) - serializer.save(module=module) - + return Lesson.objects.none() # Return no results if the module does not exist + + # Verify that the lesson exists and is associated with the module + lesson = Lesson.objects.filter(id=lesson_id, module=module).first() + 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): queryset = Enrollment.objects.all() serializer_class = EnrollmentSerializer 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): - # 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') # Check if the student and course exist try: - student = User.objects.get(id=student_id, role='student') 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: - return Response({"error": "Course not found"}, status=status.HTTP_404_NOT_FOUND) - - # Ensure the current instructor is the course instructor - if course.instructor != request.user: - return Response({"error": "You can only enroll students in your own courses"}, status=status.HTTP_403_FORBIDDEN) + return Response({"detail": "Course not found"}, status=status.HTTP_404_NOT_FOUND) + if Enrollment.objects.filter(student=request.user, course=course).exists(): + return Response({"detail": "You are already subscribed to this course."}, status=status.HTTP_404_NOT_FOUND) + 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 - enrollment = Enrollment.objects.create(student=student, course=course) + enrollment = Enrollment.objects.create(student=request.user, course=course) serializer = self.get_serializer(enrollment) 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): - # 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 enrollment = self.get_object() - - # Ensure the current instructor is the course instructor - if enrollment.course.instructor != request.user: - return Response({"error": "You can only delete enrollments in your own courses"}, status=status.HTTP_403_FORBIDDEN) + if enrollment.student != request.user: + raise PermissionDenied("You do not have permission to delete this enrollment.") # Delete the enrollment 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): queryset = Quiz.objects.all() @@ -279,19 +164,19 @@ class QuizViewSet(ModelViewSet): permission_classes = [IsAuthenticated] def create(self, request, *args, **kwargs): - # Ensure the user is an instructor - if request.user.role != 'instructor': - return Response({"error": "Only instructors can create quizzes"}, status=status.HTTP_403_FORBIDDEN) + # Ensure the user is an owner + if request.user.role != 'owner': + return Response({"detail": "Only owners can create quizzes"}, status=status.HTTP_403_FORBIDDEN) # Get course data from the request moduleId = request.data.get('module') # Check if the course exists try: module = Module.objects.get(id=moduleId) except Course.DoesNotExist: - return Response({"error": "Course not found"}, status=status.HTTP_404_NOT_FOUND) - # Ensure the current instructor is the course instructor - if module.course.instructor != request.user: - return Response({"error": "You can only create quizzes for your own courses"}, status=status.HTTP_403_FORBIDDEN) + return Response({"detail": "Course not found"}, status=status.HTTP_404_NOT_FOUND) + # Ensure the current owner is the course owner + if module.course.owner != request.user: + return Response({"detail": "You can only create quizzes for your own courses"}, status=status.HTTP_403_FORBIDDEN) # Create a new quiz # data = request.data.copy() # نسخ البيانات لتجنب التعديل على الأصل # data.pop('module', None) # إزالة المفتاح module إذا كان موجودًا @@ -301,14 +186,14 @@ class QuizViewSet(ModelViewSet): def update(self, request, *args, **kwargs): - # Ensure the user is an instructor - if request.user.role != 'instructor': - return Response({"error": "Only instructors can update quizzes"}, status=status.HTTP_403_FORBIDDEN) + # Ensure the user is an owner + if request.user.role != 'owner': + return Response({"detail": "Only owners can update quizzes"}, status=status.HTTP_403_FORBIDDEN) # Get the quiz object to update quiz = self.get_object() - # Ensure the current instructor is the course instructor - if quiz.module.course.instructor != request.user: - return Response({"error": "You can only update quizzes for your own courses"}, status=status.HTTP_403_FORBIDDEN) + # Ensure the current owner is the course owner + if quiz.module.course.owner != request.user: + return Response({"detail": "You can only update quizzes for your own courses"}, status=status.HTTP_403_FORBIDDEN) # Update the quiz serializer = self.get_serializer(quiz, data=request.data, partial=True) serializer.is_valid(raise_exception=True) @@ -316,17 +201,17 @@ class QuizViewSet(ModelViewSet): return Response(serializer.data, status=status.HTTP_200_OK) def destroy(self, request, *args, **kwargs): - # Ensure the user is an instructor - if request.user.role != 'instructor': - return Response({"error": "Only instructors can delete quizzes"}, status=status.HTTP_403_FORBIDDEN) + # Ensure the user is an owner + if request.user.role != 'owner': + return Response({"detail": "Only owners can delete quizzes"}, status=status.HTTP_403_FORBIDDEN) # Get the quiz object to delete quiz = self.get_object() - # Ensure the current instructor is the course instructor - if quiz.module.course.instructor != request.user: - return Response({"error": "You can only delete quizzes for your own courses"}, status=status.HTTP_403_FORBIDDEN) + # Ensure the current owner is the course owner + if quiz.module.course.owner != request.user: + return Response({"detail": "You can only delete quizzes for your own courses"}, status=status.HTTP_403_FORBIDDEN) # Delete the quiz 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): @@ -336,7 +221,8 @@ class CertificateViewSet(ModelViewSet): def get_permissions(self): if self.action == 'create': - permission_classes = [IsInstructor] + # permission_classes = [Isowner] + pass elif self.action in ['update', 'destroy']: permission_classes = [IsAdmin] else: @@ -354,12 +240,12 @@ class CertificateViewSet(ModelViewSet): course = Course.objects.get(id=courseId) student = User.objects.get(id=student_id, role='student') 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: - return Response({"error": "Course not found"}, status=status.HTTP_404_NOT_FOUND) - # Ensure the current instructor is the course instructor - if course.instructor != request.user: - return Response({"error": "You can only create certificate for your own courses"}, status=status.HTTP_403_FORBIDDEN) + return Response({"detail": "Course not found"}, status=status.HTTP_404_NOT_FOUND) + # Ensure the current owner is the course owner + if course.owner != request.user: + 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) serializer = self.get_serializer(certificate)