Coverage for server / routes / student / student_classes.py: 100%
28 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-10-04 09:33 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-10-04 09:33 +0000
1from typing import Dict, Optional
2from fastapi import APIRouter, Body, Depends, HTTPException, Request, status
3from server.authentication.auth0_bearer import Auth0Bearer
4from server.services.student.student_classes import StudentClassesService
5from server.utilities.model_parser import normalize_query_params
6from server.models.classes import StudentClassListResponse
7from server.models.classes import StudentFetchbyclasscodeResponse
8from server.validators.class_code_validator import ClassCodePath
10router = APIRouter()
12student_classes_service = StudentClassesService()
15@router.get(
16 "/all/fetch",
17 dependencies=[Depends(Auth0Bearer(access_levels=["student"]))],
18 status_code=status.HTTP_200_OK,
19 description="As a student, I can fetch all classes I am enrolled in",
20 summary="As a student, I can fetch all classes I am enrolled in",
21 response_model=StudentClassListResponse,
22 response_model_exclude_none=True,
23)
24async def all_classes_fetch(
25 request: Request,
26 page_num: int = 1,
27 page_size: int = 10,
28 normalized_params: Dict[str, Optional[str]] = Depends(normalize_query_params),
29) -> dict:
30 """
31 Retrieve all classes for a student with filtering and pagination.
33 Args:
34 request (Request): The incoming request object containing student context
35 page_num (int, optional): Page number for pagination. Defaults to 1.
36 page_size (int, optional): Number of items per page. Defaults to 10.
37 normalized_params (Dict[str, Optional[str]]): Query parameters for filtering
38 - title: Filter by class title (case-insensitive partial match)
39 - status: Filter by enrollment status ("Enrolled", "Pending", or "Removed")
41 Returns:
42 dict: {
43 "data": List[ClassModel], # Classes for current page
44 "count": int, # Items in current page
45 "total": int, # Total classes for student
46 "page": int, # Current page number
47 "no_of_pages": int # Total pages
48 }
50 Raises:
51 HTTPException(400): If invalid status provided
52 HTTPException(500): For server errors
53 """
54 return await student_classes_service.all_classes_fetch(
55 request, page_num, page_size, normalized_params
56 )
59@router.get(
60 "/{class_code}/fetch",
61 dependencies=[Depends(Auth0Bearer(access_levels=["student"]))],
62 status_code=status.HTTP_200_OK,
63 description="As a student, I can fetch a class by its code",
64 summary="As a student, I can fetch a class by its code",
65 response_model=StudentFetchbyclasscodeResponse,
66 response_model_exclude_none=True,
67)
68async def student_class_fetch(request: Request, class_code: ClassCodePath) -> dict:
69 """
70 Retrieve details of a specific class by its class code.
72 Args:
73 request (Request): The incoming request object containing student context
74 class_code (str): Unique code identifying the class to fetch
76 Returns:
77 dict: {
78 "Class": ClassModel, # Class details if found
79 "message": str # Status message if class not found
80 }
82 Raises:
83 HTTPException(400): If invalid class code format
84 HTTPException(500): For server errors
85 """
86 return await student_classes_service.class_fetch(request, class_code)
89@router.patch(
90 "/{class_code}/join",
91 dependencies=[Depends(Auth0Bearer(access_levels=["student"]))],
92 status_code=status.HTTP_200_OK,
93 description="As a student, I can join a class using its code",
94 summary="As a student, I can join a class using its code",
95)
96async def class_join(class_code: ClassCodePath, request: Request) -> dict:
97 """
98 Join a class using its code.
100 This endpoint allows students to join a class by providing a valid class code. The code is
101 validated and if valid, the student is enrolled in the class. Students can only join classes
102 that are currently active and accepting new enrollments.
104 Args:
105 class_code (str): Unique code identifying the class to join
106 - Must be a valid, active class code
107 - Case-sensitive alphanumeric string
108 request (Request): The incoming request object containing:
109 - JWT token in Authorization header
110 - Student authentication context
111 - Student role and permissions
113 Returns:
114 dict: Response containing:
115 - status (str): Success/failure status
116 - message (str): Descriptive message
117 - class_details (dict): Information about the joined class
118 - name (str): Class name
119 - teacher (str): Teacher's name
120 - schedule (str): Class schedule
121 - location (str): Class location
123 Raises:
124 HTTPException:
125 - 400: If class code is invalid or expired
126 - 401: If authentication token is invalid
127 - 403: If user lacks student permissions
128 - 409: If student is already enrolled
129 - 422: If class is full or not accepting students
130 """
131 return await student_classes_service.join(class_code, request)
134@router.patch(
135 "/{class_code}/leave",
136 dependencies=[Depends(Auth0Bearer(access_levels=["student"]))],
137 status_code=status.HTTP_200_OK,
138 description="As a student, I can request to leave a class",
139 summary="As a student, I can request to leave a class",
140)
141async def class_leave_request(class_code: ClassCodePath, request: Request) -> dict:
142 """Submit a request to leave a class.
144 This endpoint allows students to request removal from a class they are currently enrolled in.
145 The request will need to be approved by the teacher before the student is officially removed.
147 Args:
148 class_code (str): The unique code identifying the class
149 request (Request): The FastAPI request object containing the authenticated student's information
151 Returns:
152 dict: A response containing the status of the leave request
153 Example: {"status": "success", "message": "Leave request submitted successfully"}
155 Raises:
156 HTTPException:
157 - 404 if the class is not found
158 - 400 if the student is not enrolled in the class
159 - 409 if a leave request is already pending
160 """
161 return await student_classes_service.leave(class_code, request)
164@router.patch(
165 "/join/{class_code}/cancel",
166 dependencies=[Depends(Auth0Bearer(access_levels=["student"]))],
167 status_code=status.HTTP_200_OK,
168 description="As a student, I can cancel a pending request to join a class",
169 summary="As a student, I can cancel a pending request to join a class",
170)
171async def join_cancel(class_code: ClassCodePath, request: Request) -> dict:
172 """
173 Cancel a pending request to join a class.
175 This endpoint allows students to cancel their outstanding join request for a specific class.
176 The request will be removed from the pending queue and the student will remain unenrolled.
178 Args:
179 class_code (str): The unique code identifying the class
180 request (Request): The FastAPI request object containing:
181 - JWT token in Authorization header
182 - Student authentication context
183 - Student role and permissions
185 Returns:
186 dict: Response containing cancellation status
187 Example: {
188 "status": "success",
189 "message": "Join request cancelled successfully"
190 }
192 Raises:
193 HTTPException:
194 - 404: If the class code is not found
195 - 400: If no pending join request exists
196 - 401: If authentication token is invalid
197 - 403: If user lacks student permissions
198 """
199 return await student_classes_service.join_cancel(class_code, request)
202@router.get(
203 "/messages/{class_uuid}/fetch",
204 dependencies=[Depends(Auth0Bearer(access_levels=["student"]))],
205 status_code=status.HTTP_200_OK,
206 description="As a student, I can fetch announcements for a class I am enrolled in",
207 summary="As a student, I can fetch class announcements",
208)
209async def class_messages_fetch(
210 request: Request,
211 class_uuid: str,
212) -> dict:
213 """
214 Retrieve announcements for a specific class the student is enrolled in.
216 Args:
217 request (Request): The incoming request object containing student context
218 class_uuid (str): Unique identifier for the class
220 Returns:
221 dict: {
222 "messages": list of ClassMessage objects,
223 "count": int
224 }
226 Raises:
227 HTTPException:
228 - 400: Invalid class UUID format
229 - 401: Invalid or missing authentication token
230 - 404: Class not found or student not enrolled
231 """
232 return await student_classes_service.messages_fetch(request, class_uuid)