This commit is contained in:
AN 2025-01-15 14:34:15 +00:00 committed by GitHub
parent 11c20c0474
commit f038e97354
7 changed files with 57 additions and 19 deletions

View file

@ -10,13 +10,13 @@ class CourseAdmin(admin.ModelAdmin):
@admin.register(Module) @admin.register(Module)
class ModuleAdmin(admin.ModelAdmin): class ModuleAdmin(admin.ModelAdmin):
list_display = ('id', 'title', 'course', 'order') list_display = ('id', 'title', 'course')
search_fields = ('title', 'course__title') search_fields = ('title', 'course__title')
list_filter = ('course',) list_filter = ('course',)
@admin.register(Lesson) @admin.register(Lesson)
class LessonAdmin(admin.ModelAdmin): class LessonAdmin(admin.ModelAdmin):
list_display = ('title', 'module', 'order') list_display = ('title', 'module')
search_fields = ('title', 'module__title') search_fields = ('title', 'module__title')
list_filter = ('module',) list_filter = ('module',)

View file

@ -0,0 +1,21 @@
# Generated by Django 5.0.10 on 2025-01-14 17:20
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('app', '0009_lesson_description_alter_module_description'),
]
operations = [
migrations.RemoveField(
model_name='lesson',
name='order',
),
migrations.RemoveField(
model_name='module',
name='order',
),
]

View file

@ -35,7 +35,6 @@ class Module(models.Model):
title = models.CharField(max_length=255, verbose_name="Module Title") title = models.CharField(max_length=255, verbose_name="Module Title")
description = models.TextField(null=True, 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)
created_by = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, verbose_name="Created By") created_by = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, verbose_name="Created By")
def str(self): def str(self):
@ -48,7 +47,6 @@ class Lesson(models.Model):
description = models.TextField(null=True, verbose_name="Lesson Description") 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")
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") created_by = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, verbose_name="Created By")

View file

@ -20,6 +20,9 @@ class IsOwnerOrReadOnly(BasePermission):
case "LessonViewSet": case "LessonViewSet":
return obj.created_by == request.user return obj.created_by == request.user
case "EnrollmentViewSet":
return obj.student == request.user

View file

@ -24,20 +24,21 @@ class LessonSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Lesson model = Lesson
fields = ['id', 'title', 'description', 'content', 'module', 'order', 'file'] fields = ['id', 'title', 'description', 'content', 'module', 'file']
class ModuleSerializer(serializers.ModelSerializer): class ModuleSerializer(serializers.ModelSerializer):
lessons = serializers.SerializerMethodField() lessons = serializers.SerializerMethodField()
class Meta: class Meta:
model = Module model = Module
fields = ['id', 'title', 'description', 'lessons', 'course', 'order'] fields = ['id', 'title', 'description', 'lessons', 'course']
read_only_fields = ['course', 'lessons'] read_only_fields = ['course', 'lessons']
def get_lessons(self, obj): def get_lessons(self, obj):
return obj.lessons.values('id', 'title', 'description') return obj.lessons.values('id', 'title', 'description')
class EnrollmentSerializer(serializers.ModelSerializer): class EnrollmentSerializer(serializers.ModelSerializer):
course_details = serializers.SerializerMethodField() course_details = serializers.SerializerMethodField()
class Meta: class Meta:

3
lms/app/signals.py Normal file
View file

@ -0,0 +1,3 @@
from django.db.models.signals import pre_save
from django.dispatch import receiver
from .model import Module

View file

@ -55,7 +55,7 @@ class ModuleViewSet(ModelViewSet):
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:
return Module.objects.filter(course=course).order_by('order') return Module.objects.filter(course=course)
return Module.objects.none() return Module.objects.none()
@ -65,6 +65,10 @@ class ModuleViewSet(ModelViewSet):
""" """
course_id = self.request.data.get('course') course_id = self.request.data.get('course')
course = Course.objects.filter(id=course_id, owner=self.request.user).first() course = Course.objects.filter(id=course_id, owner=self.request.user).first()
is_owner = course.owner == self.request.user
if not is_owner:
raise PermissionDenied("You do not have permission to create module.")
if not course: if not course:
return Response( return Response(
{"detail": "This course not found."}, {"detail": "This course not found."},
@ -108,9 +112,26 @@ class LessonViewSet(ModelViewSet):
is_enrolled = Enrollment.objects.filter(course=module.course, student=self.request.user).exists() is_enrolled = Enrollment.objects.filter(course=module.course, student=self.request.user).exists()
if is_owner or is_enrolled: if is_owner or is_enrolled:
return Lesson.objects.filter(id=lesson_id) # Return the lesson if the user is authorized 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 return Lesson.objects.none() # Deny access if the user is not authorized
def perform_create(self, serializer):
"""
Customize the creation of a lesson to include the module and the user who created it.
"""
module_id = self.request.data.get('module') # Get the module ID from the request
module = Module.objects.filter(id=module_id).first() # Fetch the module
is_owner = module.course.owner == self.request.user
if not is_owner:
raise PermissionDenied("You do not have permission to create lessons in this module.")
if not module:
raise serializers.ValidationError({"module": "Module does not exist."})
# Save the lesson with the module and created_by user
serializer.save(module=module, created_by=self.request.user)
@ -120,10 +141,10 @@ class EnrollmentViewSet(ModelViewSet):
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
http_method_names = ['get', 'post', 'delete'] http_method_names = ['get', 'post', 'delete']
def retrieve(self, request, *args, **kwargs): def list(self, request, *args, **kwargs):
instance = Enrollment.objects.filter(user=request.user) instance = Enrollment.objects.filter(student=request.user)
serializer = self.get_serializer(instance) serializer = self.get_serializer(instance, many=True)
return Response(serializer.data) return Response(serializer.data)
@ -147,15 +168,6 @@ class EnrollmentViewSet(ModelViewSet):
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 destroy(self, request, *args, **kwargs):
# Get the enrollment object to delete
enrollment = self.get_object()
if enrollment.student != request.user:
raise PermissionDenied("You do not have permission to delete this enrollment.")
# Delete the enrollment
enrollment.delete()
return Response({"detail": "Enrollment deleted successfully"}, status=status.HTTP_204_NO_CONTENT)
class QuizViewSet(ModelViewSet): class QuizViewSet(ModelViewSet):