Browse Source

swagger problem resolved with adding ref_name to views

master
Mohsen Taba 2 months ago
parent
commit
011b25d017
  1. 70
      apps/account/permissions.py
  2. 42
      apps/account/views/user.py
  3. 9
      apps/blog/views_admin.py
  4. 13
      apps/certificate/views.py
  5. 3
      apps/course/serializers/admin.py
  6. 127
      apps/course/views/admin.py
  7. 1
      apps/quiz/serializers/admin.py
  8. 47
      apps/quiz/views/admin.py
  9. 14
      apps/transaction/views.py

70
apps/account/permissions.py

@ -1,12 +1,58 @@
from rest_framework.permissions import BasePermission
class IsActiveUser(BasePermission):
def has_permission(self, request, view):
return request.user and request.user.is_active
from rest_framework.permissions import BasePermission, SAFE_METHODS
class IsActiveUser(BasePermission):
def has_permission(self, request, view):
return request.user and request.user.is_active
class IsSuperAdmin(BasePermission):
"""
Allows access only to super admins and staff admins.
"""
def has_permission(self, request, view):
return (
request.user and
request.user.is_authenticated and
request.user.is_active and
(request.user.is_superuser or request.user.user_type in ['super_admin', 'admin'])
)
class IsPanelUser(BasePermission):
"""
Allows access to all administrative panel roles: super admins, admins, and professors.
"""
def has_permission(self, request, view):
return (
request.user and
request.user.is_authenticated and
request.user.is_active and
(request.user.is_superuser or request.user.user_type in ['super_admin', 'admin', 'professor'])
)
class IsSuperAdminOrReadOnlyForProfessor(BasePermission):
"""
Allows full read-write access to super admins/admins,
but only read-only (GET, HEAD, OPTIONS) access to professors.
"""
def has_permission(self, request, view):
if not request.user or not request.user.is_authenticated or not request.user.is_active:
return False
# Super admin / Admin can do everything
if request.user.is_superuser or request.user.user_type in ['super_admin', 'admin']:
return True
# Professor has read-only access
if request.user.user_type == 'professor':
return request.method in SAFE_METHODS
return False

42
apps/account/views/user.py

@ -29,7 +29,7 @@ from utils.redis import RedisManager
from utils.exceptions import AppAPIException from utils.exceptions import AppAPIException
from utils import send_email, is_valid_email from utils import send_email, is_valid_email
from config.settings import base as settings from config.settings import base as settings
from apps.account.permissions import IsActiveUser
from apps.account.permissions import IsActiveUser, IsSuperAdminOrReadOnlyForProfessor
from apps.account.doc import * from apps.account.doc import *
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -424,7 +424,7 @@ class UserLoginView(CreateAPIView):
"fullname": user.fullname, "fullname": user.fullname,
"email": user.email, "email": user.email,
"token": token.key, "token": token.key,
"user_type": user.user_type_based_on_groups,
"user_type": user.user_type,
"avatar": request.build_absolute_uri(user.avatar.url) if user.avatar else None, "avatar": request.build_absolute_uri(user.avatar.url) if user.avatar else None,
}, status=status.HTTP_201_CREATED) }, status=status.HTTP_201_CREATED)
@ -583,18 +583,27 @@ class AdminLoginView(CreateAPIView):
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
data = serializer.data data = serializer.data
email = request.data['email']
email = request.data['email'].strip().lower()
try: try:
user_obj = User.objects.get(email=email)
user_obj = User.objects.get(email__iexact=email)
except User.DoesNotExist: except User.DoesNotExist:
raise ValidationError({"email": "No admin found with that information."}) raise ValidationError({"email": "No admin found with that information."})
# --- THE CRUCIAL ADMIN CHECK ---
# Adjust 'is_staff' or 'is_superuser' based on how you define admins in Django
if not (user_obj.is_staff or user_obj.is_superuser):
# --- PANEL ACCESS CHECK ---
# Allow super_admin, admin (is_staff/is_superuser), professors
# Check both user_type field AND group membership (in case they differ)
ALLOWED_TYPES = ('professor', 'admin', 'super_admin')
is_panel_user = (
user_obj.is_staff or
user_obj.is_superuser or
getattr(user_obj, 'user_type', None) in ALLOWED_TYPES or
user_obj.groups.filter(name="Professor Group").exists()
)
if not is_panel_user:
raise AuthenticationFailed("No admin found with that information.") raise AuthenticationFailed("No admin found with that information.")
user = authenticate(request, username=email, password=data['password'])
# Use the actual stored email for authentication (ensures case matches DB)
user = authenticate(request, username=user_obj.email, password=data['password'])
if not user: if not user:
raise ValidationError({"password": "Password is incorrect"}) raise ValidationError({"password": "Password is incorrect"})
@ -612,12 +621,18 @@ class AdminLoginView(CreateAPIView):
device_os='web_admin' device_os='web_admin'
) )
# Determine effective user_type (user_type field may lag behind groups)
effective_user_type = user.user_type
if effective_user_type not in ('professor', 'admin', 'super_admin'):
if user.groups.filter(name="Professor Group").exists():
effective_user_type = 'professor'
return Response({ return Response({
"id": user.id, "id": user.id,
"fullname": user.fullname, "fullname": user.fullname,
"email": user.email, "email": user.email,
"token": token.key, "token": token.key,
"user_type": user.user_type_based_on_groups,
"user_type": effective_user_type,
"avatar": request.build_absolute_uri(user.avatar.url) if user.avatar else None, "avatar": request.build_absolute_uri(user.avatar.url) if user.avatar else None,
}, status=status.HTTP_201_CREATED) }, status=status.HTTP_201_CREATED)
@ -634,7 +649,7 @@ class AdminUserViewSet(ModelViewSet):
Includes searching, filtering, and pagination. Includes searching, filtering, and pagination.
""" """
serializer_class = AdminUserSerializer serializer_class = AdminUserSerializer
permission_classes = [IsAuthenticated, IsAdminUser] # Strictly admin only
permission_classes = [IsAuthenticated, IsSuperAdminOrReadOnlyForProfessor]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
pagination_class = StandardResultsSetPagination pagination_class = StandardResultsSetPagination
filter_backends = [] # Disable default backend filtering to use custom manual filtering filter_backends = [] # Disable default backend filtering to use custom manual filtering
@ -642,6 +657,13 @@ class AdminUserViewSet(ModelViewSet):
def get_queryset(self): def get_queryset(self):
queryset = User.objects.filter(is_active=True, email__isnull=False).exclude(email='') queryset = User.objects.filter(is_active=True, email__isnull=False).exclude(email='')
# Restrict queryset for professors to only students of their courses
if self.request.user.user_type == 'professor':
queryset = queryset.filter(
user_type='student',
participated_courses__course__professor_id=self.request.user.id
)
# Handle Search # Handle Search
search_query = self.request.query_params.get('search', None) search_query = self.request.query_params.get('search', None)
if search_query: if search_query:

9
apps/blog/views_admin.py

@ -1,6 +1,7 @@
from django.db.models import Q from django.db.models import Q
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.permissions import IsAuthenticated
from apps.account.permissions import IsSuperAdmin
from rest_framework.authentication import TokenAuthentication from rest_framework.authentication import TokenAuthentication
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
from rest_framework.decorators import action from rest_framework.decorators import action
@ -19,7 +20,7 @@ class AdminBlogViewSet(ModelViewSet):
""" """
Admin CRUD ViewSet for Blog management. Admin CRUD ViewSet for Blog management.
""" """
permission_classes = [IsAuthenticated, IsAdminUser]
permission_classes = [IsAuthenticated, IsSuperAdmin]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
pagination_class = StandardResultsSetPagination pagination_class = StandardResultsSetPagination
# Allow multipart so admins can upload thumbnail images directly # Allow multipart so admins can upload thumbnail images directly
@ -63,7 +64,7 @@ class AdminBlogContentViewSet(ModelViewSet):
Admin CRUD ViewSet for managing the content blocks inside a specific blog. Admin CRUD ViewSet for managing the content blocks inside a specific blog.
""" """
serializer_class = AdminBlogContentSerializer serializer_class = AdminBlogContentSerializer
permission_classes = [IsAuthenticated, IsAdminUser]
permission_classes = [IsAuthenticated, IsSuperAdmin]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
parser_classes = (MultiPartParser, FormParser, JSONParser) parser_classes = (MultiPartParser, FormParser, JSONParser)
@ -103,7 +104,7 @@ class AdminBlogSeoViewSet(ModelViewSet):
Admin CRUD ViewSet for managing SEO meta tags for a specific blog. Admin CRUD ViewSet for managing SEO meta tags for a specific blog.
""" """
serializer_class = AdminBlogSeoSerializer serializer_class = AdminBlogSeoSerializer
permission_classes = [IsAuthenticated, IsAdminUser]
permission_classes = [IsAuthenticated, IsSuperAdmin]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
def get_queryset(self): def get_queryset(self):

13
apps/certificate/views.py

@ -56,19 +56,28 @@ class UserCertificatesListView(generics.ListAPIView):
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAdminUser
from apps.certificate.serializers import AdminCertificateSerializer from apps.certificate.serializers import AdminCertificateSerializer
from apps.account.permissions import IsPanelUser
from django.db.models import Q from django.db.models import Q
def is_professor(request):
return getattr(request.user, 'user_type', None) == 'professor'
class AdminCertificateViewSet(ModelViewSet): class AdminCertificateViewSet(ModelViewSet):
queryset = Certificate.objects.all() queryset = Certificate.objects.all()
serializer_class = AdminCertificateSerializer serializer_class = AdminCertificateSerializer
permission_classes = [permissions.IsAuthenticated, IsAdminUser]
permission_classes = [permissions.IsAuthenticated, IsPanelUser]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
pagination_class = StandardResultsSetPagination pagination_class = StandardResultsSetPagination
def get_queryset(self): def get_queryset(self):
queryset = Certificate.objects.all().select_related('student', 'course') queryset = Certificate.objects.all().select_related('student', 'course')
# Professors can only see certificates for students in their courses
if is_professor(self.request):
queryset = queryset.filter(course__professor_id=self.request.user.id)
# Search query # Search query
search_query = self.request.query_params.get('search', None) search_query = self.request.query_params.get('search', None)

3
apps/course/serializers/admin.py

@ -152,6 +152,9 @@ class AdminCourseLessonSerializer(serializers.Serializer):
video_link = serializers.CharField(max_length=500, required=False, allow_blank=True, allow_null=True) video_link = serializers.CharField(max_length=500, required=False, allow_blank=True, allow_null=True)
duration = serializers.IntegerField(min_value=0, required=False, default=0) duration = serializers.IntegerField(min_value=0, required=False, default=0)
class Meta:
ref_name = 'CourseAdminCourseLesson'
def to_representation(self, instance): def to_representation(self, instance):
""" """
Map a CourseLesson instance to representation fields. Map a CourseLesson instance to representation fields.

127
apps/course/views/admin.py

@ -1,10 +1,12 @@
from django.db.models import Q from django.db.models import Q
from rest_framework import viewsets from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.permissions import IsAuthenticated
from rest_framework.authentication import TokenAuthentication from rest_framework.authentication import TokenAuthentication
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.exceptions import PermissionDenied
from utils.pagination import StandardResultsSetPagination from utils.pagination import StandardResultsSetPagination
from apps.account.permissions import IsPanelUser, IsSuperAdminOrReadOnlyForProfessor
from apps.course.models import ( from apps.course.models import (
Course, Course,
CourseCategory, CourseCategory,
@ -34,11 +36,17 @@ from apps.course.serializers.admin import (
AdminLiveSessionDetailSerializer AdminLiveSessionDetailSerializer
) )
def is_professor(request):
return getattr(request.user, 'user_type', None) == 'professor'
class AdminCourseViewSet(viewsets.ModelViewSet): class AdminCourseViewSet(viewsets.ModelViewSet):
""" """
Admin CRUD ViewSet for Course management. Admin CRUD ViewSet for Course management.
Professors can only access/modify their own courses.
""" """
permission_classes = [IsAuthenticated, IsAdminUser]
permission_classes = [IsAuthenticated, IsPanelUser]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
pagination_class = StandardResultsSetPagination pagination_class = StandardResultsSetPagination
@ -50,6 +58,10 @@ class AdminCourseViewSet(viewsets.ModelViewSet):
def get_queryset(self): def get_queryset(self):
queryset = Course.objects.all().select_related('category', 'professor') queryset = Course.objects.all().select_related('category', 'professor')
# Professors can only see their own courses
if is_professor(self.request):
queryset = queryset.filter(professor_id=self.request.user.id)
# Search Query # Search Query
search_query = self.request.query_params.get('search', None) search_query = self.request.query_params.get('search', None)
if search_query: if search_query:
@ -81,18 +93,41 @@ class AdminCourseViewSet(viewsets.ModelViewSet):
return queryset.order_by('-id') return queryset.order_by('-id')
def perform_create(self, serializer):
# If the logged-in user is a professor, force the professor field to themselves
if is_professor(self.request):
serializer.save(professor_id=self.request.user.id)
else:
serializer.save()
def perform_update(self, serializer):
# Prevent professors from reassigning a course to another professor
if is_professor(self.request):
instance = self.get_object()
if instance.professor_id != self.request.user.id:
raise PermissionDenied("You can only edit your own courses.")
serializer.save(professor_id=self.request.user.id)
else:
serializer.save()
class AdminChapterViewSet(viewsets.ModelViewSet): class AdminChapterViewSet(viewsets.ModelViewSet):
""" """
Admin CRUD ViewSet for Course Chapters. Admin CRUD ViewSet for Course Chapters.
Professors can only access chapters of their own courses.
""" """
permission_classes = [IsAuthenticated, IsAdminUser]
permission_classes = [IsAuthenticated, IsPanelUser]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
serializer_class = AdminCourseChapterSerializer serializer_class = AdminCourseChapterSerializer
pagination_class = None pagination_class = None
def get_queryset(self): def get_queryset(self):
queryset = CourseChapter.objects.all() queryset = CourseChapter.objects.all()
# Professors can only see chapters of their own courses
if is_professor(self.request):
queryset = queryset.filter(course__professor_id=self.request.user.id)
course_id = self.request.query_params.get('course', None) course_id = self.request.query_params.get('course', None)
if course_id: if course_id:
queryset = queryset.filter(course_id=course_id) queryset = queryset.filter(course_id=course_id)
@ -119,15 +154,20 @@ class AdminChapterViewSet(viewsets.ModelViewSet):
class AdminCourseLessonViewSet(viewsets.ModelViewSet): class AdminCourseLessonViewSet(viewsets.ModelViewSet):
""" """
Admin CRUD ViewSet for Lessons associated with a Course/Chapter. Admin CRUD ViewSet for Lessons associated with a Course/Chapter.
Professors can only access lessons in their own courses.
""" """
permission_classes = [IsAuthenticated, IsAdminUser]
permission_classes = [IsAuthenticated, IsPanelUser]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
serializer_class = AdminCourseLessonSerializer serializer_class = AdminCourseLessonSerializer
pagination_class = None pagination_class = None
def get_queryset(self): def get_queryset(self):
queryset = CourseLesson.objects.all().select_related('lesson', 'chapter') queryset = CourseLesson.objects.all().select_related('lesson', 'chapter')
# Professors can only see lessons of their own courses
if is_professor(self.request):
queryset = queryset.filter(course__professor_id=self.request.user.id)
course_id = self.request.query_params.get('course', None) course_id = self.request.query_params.get('course', None)
if course_id: if course_id:
queryset = queryset.filter(course_id=course_id) queryset = queryset.filter(course_id=course_id)
@ -166,14 +206,20 @@ class AdminCourseLessonViewSet(viewsets.ModelViewSet):
class AdminCourseAttachmentViewSet(viewsets.ModelViewSet): class AdminCourseAttachmentViewSet(viewsets.ModelViewSet):
""" """
Admin CRUD ViewSet for Course Attachments. Admin CRUD ViewSet for Course Attachments.
Professors can only access attachments of their own courses.
""" """
permission_classes = [IsAuthenticated, IsAdminUser]
permission_classes = [IsAuthenticated, IsPanelUser]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
serializer_class = AdminCourseAttachmentSerializer serializer_class = AdminCourseAttachmentSerializer
pagination_class = None pagination_class = None
def get_queryset(self): def get_queryset(self):
queryset = CourseAttachment.objects.all().select_related('attachment') queryset = CourseAttachment.objects.all().select_related('attachment')
# Professors can only see attachments of their own courses
if is_professor(self.request):
queryset = queryset.filter(course__professor_id=self.request.user.id)
course_id = self.request.query_params.get('course', None) course_id = self.request.query_params.get('course', None)
if course_id: if course_id:
queryset = queryset.filter(course_id=course_id) queryset = queryset.filter(course_id=course_id)
@ -190,14 +236,20 @@ class AdminCourseAttachmentViewSet(viewsets.ModelViewSet):
class AdminCourseGlossaryViewSet(viewsets.ModelViewSet): class AdminCourseGlossaryViewSet(viewsets.ModelViewSet):
""" """
Admin CRUD ViewSet for Course Glossary terms. Admin CRUD ViewSet for Course Glossary terms.
Professors can only access glossaries of their own courses.
""" """
permission_classes = [IsAuthenticated, IsAdminUser]
permission_classes = [IsAuthenticated, IsPanelUser]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
serializer_class = AdminCourseGlossarySerializer serializer_class = AdminCourseGlossarySerializer
pagination_class = None pagination_class = None
def get_queryset(self): def get_queryset(self):
queryset = CourseGlossary.objects.all().select_related('glossary') queryset = CourseGlossary.objects.all().select_related('glossary')
# Professors can only see glossaries of their own courses
if is_professor(self.request):
queryset = queryset.filter(course__professor_id=self.request.user.id)
course_id = self.request.query_params.get('course', None) course_id = self.request.query_params.get('course', None)
if course_id: if course_id:
queryset = queryset.filter(course_id=course_id) queryset = queryset.filter(course_id=course_id)
@ -214,12 +266,13 @@ class AdminCourseGlossaryViewSet(viewsets.ModelViewSet):
class AdminCourseCategoryViewSet(viewsets.ModelViewSet): class AdminCourseCategoryViewSet(viewsets.ModelViewSet):
""" """
Admin CRUD ViewSet for Course Categories. Admin CRUD ViewSet for Course Categories.
Professors have read-only access.
""" """
permission_classes = [IsAuthenticated, IsAdminUser]
permission_classes = [IsAuthenticated, IsSuperAdminOrReadOnlyForProfessor]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
serializer_class = AdminCourseCategorySerializer serializer_class = AdminCourseCategorySerializer
pagination_class = StandardResultsSetPagination pagination_class = StandardResultsSetPagination
def get_queryset(self): def get_queryset(self):
queryset = CourseCategory.objects.all().order_by('-id') queryset = CourseCategory.objects.all().order_by('-id')
search = self.request.query_params.get('search', None) search = self.request.query_params.get('search', None)
@ -230,37 +283,53 @@ class AdminCourseCategoryViewSet(viewsets.ModelViewSet):
class AdminLessonViewSet(viewsets.ModelViewSet): class AdminLessonViewSet(viewsets.ModelViewSet):
""" """
Admin CRUD ViewSet for base Lesson.
Admin CRUD ViewSet for base Lesson (Repository).
Professors can only see lessons linked to their own courses.
""" """
permission_classes = [IsAuthenticated, IsAdminUser]
permission_classes = [IsAuthenticated, IsPanelUser]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
serializer_class = AdminLessonSerializer serializer_class = AdminLessonSerializer
pagination_class = StandardResultsSetPagination pagination_class = StandardResultsSetPagination
def get_queryset(self): def get_queryset(self):
queryset = Lesson.objects.all().order_by('-id') queryset = Lesson.objects.all().order_by('-id')
# Professors can only see lessons associated with their own courses
if is_professor(self.request):
queryset = queryset.filter(
course_lessons__course__professor_id=self.request.user.id
).distinct()
search = self.request.query_params.get('search', None) search = self.request.query_params.get('search', None)
if search: if search:
queryset = queryset.filter(title__icontains=search) queryset = queryset.filter(title__icontains=search)
content_type = self.request.query_params.get('content_type', None) content_type = self.request.query_params.get('content_type', None)
if content_type: if content_type:
queryset = queryset.filter(content_type=content_type) queryset = queryset.filter(content_type=content_type)
return queryset return queryset
class AdminGlossaryViewSet(viewsets.ModelViewSet): class AdminGlossaryViewSet(viewsets.ModelViewSet):
""" """
Admin CRUD ViewSet for base Glossary.
Admin CRUD ViewSet for base Glossary (Repository).
Professors can only see glossaries linked to their own courses.
""" """
permission_classes = [IsAuthenticated, IsAdminUser]
permission_classes = [IsAuthenticated, IsPanelUser]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
serializer_class = AdminGlossarySerializer serializer_class = AdminGlossarySerializer
pagination_class = StandardResultsSetPagination pagination_class = StandardResultsSetPagination
def get_queryset(self): def get_queryset(self):
queryset = Glossary.objects.all().order_by('-id') queryset = Glossary.objects.all().order_by('-id')
# Professors can only see glossaries associated with their own courses
if is_professor(self.request):
queryset = queryset.filter(
course_glossaries__course__professor_id=self.request.user.id
).distinct()
search = self.request.query_params.get('search', None) search = self.request.query_params.get('search', None)
if search: if search:
queryset = queryset.filter(Q(title__icontains=search) | Q(description__icontains=search)) queryset = queryset.filter(Q(title__icontains=search) | Q(description__icontains=search))
@ -269,15 +338,23 @@ class AdminGlossaryViewSet(viewsets.ModelViewSet):
class AdminAttachmentViewSet(viewsets.ModelViewSet): class AdminAttachmentViewSet(viewsets.ModelViewSet):
""" """
Admin CRUD ViewSet for base Attachment.
Admin CRUD ViewSet for base Attachment (Repository).
Professors can only see attachments linked to their own courses.
""" """
permission_classes = [IsAuthenticated, IsAdminUser]
permission_classes = [IsAuthenticated, IsPanelUser]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
serializer_class = AdminAttachmentSerializer serializer_class = AdminAttachmentSerializer
pagination_class = StandardResultsSetPagination pagination_class = StandardResultsSetPagination
def get_queryset(self): def get_queryset(self):
queryset = Attachment.objects.all().order_by('-id') queryset = Attachment.objects.all().order_by('-id')
# Professors can only see attachments associated with their own courses
if is_professor(self.request):
queryset = queryset.filter(
course_attachments__course__professor_id=self.request.user.id
).distinct()
search = self.request.query_params.get('search', None) search = self.request.query_params.get('search', None)
if search: if search:
queryset = queryset.filter(title__icontains=search) queryset = queryset.filter(title__icontains=search)
@ -287,8 +364,9 @@ class AdminAttachmentViewSet(viewsets.ModelViewSet):
class AdminLiveSessionViewSet(viewsets.ModelViewSet): class AdminLiveSessionViewSet(viewsets.ModelViewSet):
""" """
Admin CRUD ViewSet for Course Live Sessions. Admin CRUD ViewSet for Course Live Sessions.
Professors can only access live sessions of their own courses.
""" """
permission_classes = [IsAuthenticated, IsAdminUser]
permission_classes = [IsAuthenticated, IsPanelUser]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
pagination_class = StandardResultsSetPagination pagination_class = StandardResultsSetPagination
@ -299,7 +377,11 @@ class AdminLiveSessionViewSet(viewsets.ModelViewSet):
def get_queryset(self): def get_queryset(self):
queryset = CourseLiveSession.objects.all().select_related('course') queryset = CourseLiveSession.objects.all().select_related('course')
# Professors can only see live sessions of their own courses
if is_professor(self.request):
queryset = queryset.filter(course__professor_id=self.request.user.id)
search = self.request.query_params.get('search', None) search = self.request.query_params.get('search', None)
if search: if search:
queryset = queryset.filter( queryset = queryset.filter(
@ -329,4 +411,3 @@ class AdminLiveSessionViewSet(viewsets.ModelViewSet):
queryset = queryset.filter(ended_at__lte=ended_before) queryset = queryset.filter(ended_at__lte=ended_before)
return queryset.order_by('-started_at') return queryset.order_by('-started_at')

1
apps/quiz/serializers/admin.py

@ -16,6 +16,7 @@ class AdminCourseLessonSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = CourseLesson model = CourseLesson
fields = ['id', 'title'] fields = ['id', 'title']
ref_name = 'QuizAdminCourseLesson'
def get_title(self, obj): def get_title(self, obj):
if obj.title: if obj.title:

47
apps/quiz/views/admin.py

@ -1,7 +1,7 @@
from django.db.models import Q from django.db.models import Q
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from rest_framework.generics import ListAPIView from rest_framework.generics import ListAPIView
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.permissions import IsAuthenticated
from rest_framework.authentication import TokenAuthentication from rest_framework.authentication import TokenAuthentication
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.response import Response from rest_framework.response import Response
@ -11,6 +11,7 @@ from utils.pagination import StandardResultsSetPagination
from apps.quiz.models import Quiz, Question, QuizParticipant from apps.quiz.models import Quiz, Question, QuizParticipant
from apps.course.models import Course, CourseLesson, Participant from apps.course.models import Course, CourseLesson, Participant
from apps.account.models import User from apps.account.models import User
from apps.account.permissions import IsPanelUser
from apps.quiz.serializers.admin import ( from apps.quiz.serializers.admin import (
AdminCourseSerializer, AdminCourseSerializer,
@ -23,12 +24,16 @@ from apps.quiz.serializers.admin import (
) )
def is_professor(request):
return getattr(request.user, 'user_type', None) == 'professor'
class AdminQuizViewSet(ModelViewSet): class AdminQuizViewSet(ModelViewSet):
""" """
Admin CRUD ViewSet for Quiz management. Admin CRUD ViewSet for Quiz management.
Includes searching, filtering, and retrieving participants/absentees list.
Professors can only access quizzes of their own courses.
""" """
permission_classes = [IsAuthenticated, IsAdminUser]
permission_classes = [IsAuthenticated, IsPanelUser]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
pagination_class = StandardResultsSetPagination pagination_class = StandardResultsSetPagination
@ -40,6 +45,10 @@ class AdminQuizViewSet(ModelViewSet):
def get_queryset(self): def get_queryset(self):
queryset = Quiz.objects.all().select_related('course', 'lesson') queryset = Quiz.objects.all().select_related('course', 'lesson')
# Professors can only see quizzes of their own courses
if is_professor(self.request):
queryset = queryset.filter(course__professor_id=self.request.user.id)
# Handle Search # Handle Search
search_query = self.request.query_params.get('search', None) search_query = self.request.query_params.get('search', None)
if search_query: if search_query:
@ -110,16 +119,20 @@ class AdminQuizViewSet(ModelViewSet):
class AdminQuestionViewSet(ModelViewSet): class AdminQuestionViewSet(ModelViewSet):
""" """
Admin CRUD ViewSet for Question management. Admin CRUD ViewSet for Question management.
Usually filtered by quiz_id.
Professors can only access questions of quizzes belonging to their own courses.
""" """
serializer_class = AdminQuestionSerializer serializer_class = AdminQuestionSerializer
permission_classes = [IsAuthenticated, IsAdminUser]
permission_classes = [IsAuthenticated, IsPanelUser]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
pagination_class = None pagination_class = None
def get_queryset(self): def get_queryset(self):
queryset = Question.objects.all() queryset = Question.objects.all()
# Professors can only see questions of their own courses' quizzes
if is_professor(self.request):
queryset = queryset.filter(quiz__course__professor_id=self.request.user.id)
quiz_id = self.request.query_params.get('quiz_id', None) quiz_id = self.request.query_params.get('quiz_id', None)
if not quiz_id: if not quiz_id:
# Fallback parameter name # Fallback parameter name
@ -162,25 +175,39 @@ class AdminQuestionViewSet(ModelViewSet):
class AdminCourseListView(ListAPIView): class AdminCourseListView(ListAPIView):
""" """
Dropdown listing helper for all courses. Dropdown listing helper for all courses.
Professors only see their own courses.
""" """
queryset = Course.objects.all().order_by('-id')
serializer_class = AdminCourseSerializer serializer_class = AdminCourseSerializer
permission_classes = [IsAuthenticated, IsAdminUser]
permission_classes = [IsAuthenticated, IsPanelUser]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
pagination_class = None # Return all courses for dropdown usage pagination_class = None # Return all courses for dropdown usage
def get_queryset(self):
queryset = Course.objects.all().order_by('-id')
if is_professor(self.request):
queryset = queryset.filter(professor_id=self.request.user.id)
return queryset
class AdminLessonListView(ListAPIView): class AdminLessonListView(ListAPIView):
""" """
Dropdown listing helper for lessons. Filtered by course_id. Dropdown listing helper for lessons. Filtered by course_id.
Professors only see lessons of their own courses.
""" """
serializer_class = AdminCourseLessonSerializer serializer_class = AdminCourseLessonSerializer
permission_classes = [IsAuthenticated, IsAdminUser]
permission_classes = [IsAuthenticated, IsPanelUser]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
pagination_class = None # Return all matching lessons for dropdown usage pagination_class = None # Return all matching lessons for dropdown usage
def get_queryset(self): def get_queryset(self):
course_id = self.request.query_params.get('course_id', None) course_id = self.request.query_params.get('course_id', None)
if course_id: if course_id:
return CourseLesson.objects.filter(course_id=course_id).select_related('lesson').order_by('priority')
return CourseLesson.objects.all().select_related('lesson').order_by('-id')
qs = CourseLesson.objects.filter(course_id=course_id).select_related('lesson').order_by('priority')
else:
qs = CourseLesson.objects.all().select_related('lesson').order_by('-id')
# Professors only see lessons of their own courses
if is_professor(self.request):
qs = qs.filter(course__professor_id=self.request.user.id)
return qs

14
apps/transaction/views.py

@ -417,19 +417,25 @@ class TransactionReceiptsListView(generics.ListAPIView):
# ============================================================================= # =============================================================================
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAdminUser
from apps.transaction.serializers import AdminTransactionSerializer from apps.transaction.serializers import AdminTransactionSerializer
from apps.account.permissions import IsPanelUser
from django.db.models import Q from django.db.models import Q
from utils.pagination import StandardResultsSetPagination from utils.pagination import StandardResultsSetPagination
def is_professor(request):
return getattr(request.user, 'user_type', None) == 'professor'
class AdminTransactionViewSet(ModelViewSet): class AdminTransactionViewSet(ModelViewSet):
""" """
Admin-only viewset for viewing and updating transactions. Admin-only viewset for viewing and updating transactions.
Only GET (list/retrieve) and PATCH (update status) are allowed. Only GET (list/retrieve) and PATCH (update status) are allowed.
Professors only see transactions for their own courses.
""" """
queryset = TransactionParticipant.objects.all() queryset = TransactionParticipant.objects.all()
serializer_class = AdminTransactionSerializer serializer_class = AdminTransactionSerializer
permission_classes = [IsAuthenticated, IsAdminUser]
permission_classes = [IsAuthenticated, IsPanelUser]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
pagination_class = StandardResultsSetPagination pagination_class = StandardResultsSetPagination
http_method_names = ['get', 'patch', 'head', 'options'] http_method_names = ['get', 'patch', 'head', 'options']
@ -437,6 +443,10 @@ class AdminTransactionViewSet(ModelViewSet):
def get_queryset(self): def get_queryset(self):
queryset = TransactionParticipant.objects.all().select_related('user', 'course').prefetch_related('receipts', 'participant_infos') queryset = TransactionParticipant.objects.all().select_related('user', 'course').prefetch_related('receipts', 'participant_infos')
# Professors can only see transactions for their own courses
if is_professor(self.request):
queryset = queryset.filter(course__professor_id=self.request.user.id)
# Search # Search
search_query = self.request.query_params.get('search', None) search_query = self.request.query_params.get('search', None)
if search_query: if search_query:

Loading…
Cancel
Save