Coverage for server / routes / teacher / teacher_classes.py: 100%

64 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-10-04 09:33 +0000

1from typing import Annotated, Dict, Optional 

2from fastapi import APIRouter, Body, Depends, File, HTTPException, Path, Request, UploadFile, status 

3from server.authentication.auth0_bearer import Auth0Bearer 

4from server.services.teacher.teacher_classes import TeacherClassesService 

5from server.models.classes import ( 

6 LeaveRequestData, 

7 RegisterClass, 

8 UpdateClassModel, 

9 UpdateStudentStatus, 

10) 

11from server.models.class_message import CreateClassMessage 

12from server.utilities.model_parser import normalize_query_params 

13from server.validators.class_code_validator import ClassCodePath 

14 

15router = APIRouter() 

16 

17teacher_classes_service = TeacherClassesService() 

18 

19@router.post( 

20 "/create", 

21 dependencies=[Depends(Auth0Bearer(access_levels=["teacher"]))], 

22 status_code=status.HTTP_201_CREATED, 

23 description="As a teacher, I can create a new class", 

24 summary="As a teacher, I can create a new class", 

25) 

26async def create_new_class(request: Request, new_class: RegisterClass): 

27 """ 

28 Create a new class with the authenticated teacher as the instructor. 

29 

30 This endpoint allows teachers to create a new class with specified details. The class 

31 will automatically be assigned to the authenticated teacher and a unique class code 

32 will be generated. 

33 

34 Args: 

35 request (Request): The incoming request object containing: 

36 - JWT token in Authorization header 

37 - Teacher authentication context 

38 - Teacher role and permissions 

39 new_class (RegisterClass): Class details for creation including: 

40 - name (str): Name/title of the class 

41 - description (str): Class description and overview 

42 - subject (str): Subject area or discipline 

43 - grade_level (int): Target grade level 

44 - schedule (dict): Class schedule details 

45 - max_students (int): Maximum enrollment capacity 

46 - status (str): Class status (e.g. "active", "draft") 

47 

48 Returns: 

49 dict: Newly created class details including: 

50 - id (str): Unique class identifier 

51 - class_code (str): Generated unique join code 

52 - name (str): Class name 

53 - teacher (dict): Assigned teacher details 

54 - created_at (datetime): Creation timestamp 

55 - status (str): Current class status 

56 

57 Raises: 

58 HTTPException: 

59 - 401: Invalid or missing authentication token 

60 - 403: User lacks teacher permissions 

61 - 422: Invalid class details provided 

62 - 500: Error creating class 

63 """ 

64 return await teacher_classes_service.create_new_class(request, new_class) 

65 

66@router.get( 

67 "/all/fetch", 

68 dependencies=[Depends(Auth0Bearer(access_levels=["teacher"]))], 

69 status_code=status.HTTP_200_OK, 

70 description="As a teacher, I can fetch all classes", 

71 summary="As a teacher, I can fetch all classes", 

72) 

73async def all_classes_fetch( 

74 request: Request, 

75 page_num: int = 1, 

76 page_size: int = 10, 

77 normalized_params: Dict[str, Optional[str]] = Depends(normalize_query_params), 

78 ) -> dict: 

79 """ 

80 Retrieve all classes for the authenticated teacher with pagination and filtering. 

81 

82 This endpoint returns a paginated list of all classes taught by the authenticated teacher. 

83 Results can be filtered and sorted using query parameters. Each class includes basic 

84 details about enrolled students and class status. 

85 

86 Args: 

87 request (Request): The incoming request object containing: 

88 - JWT token in Authorization header 

89 - Teacher authentication context 

90 - Teacher role and permissions 

91 page_num (int, optional): Page number for pagination, starting from 1. Defaults to 1. 

92 page_size (int, optional): Number of classes per page. Defaults to 10. 

93 normalized_params (Dict[str, Optional[str]]): Additional query parameters for filtering: 

94 - status (str): Filter by class status (e.g. "active", "archived") 

95 - subject (str): Filter by subject area 

96 - grade_level (int): Filter by grade level 

97 - sort (str): Sort field and direction (e.g. "name:asc", "created_at:desc") 

98 - search (str): Search classes by name or description 

99 

100 Returns: 

101 dict: Paginated class listing containing: 

102 - items (list): List of class objects with: 

103 - id (str): Unique class identifier 

104 - name (str): Class name/title 

105 - subject (str): Subject area 

106 - grade_level (int): Target grade level 

107 - student_count (int): Current enrollment count 

108 - max_students (int): Maximum capacity 

109 - status (str): Class status 

110 - created_at (datetime): Creation timestamp 

111 - total (int): Total number of classes matching filters 

112 - page (int): Current page number 

113 - pages (int): Total number of pages 

114 - has_more (bool): Whether more pages exist 

115 

116 Raises: 

117 HTTPException: 

118 - 401: Invalid or missing authentication token 

119 - 403: Insufficient permissions to list classes 

120 - 422: Invalid pagination or filter parameters 

121 - 500: Error retrieving class data 

122 """ 

123 return await teacher_classes_service.all_classes_fetch( 

124 request, page_num, page_size, normalized_params 

125 ) 

126 

127 

128@router.get( 

129 "/{class_code}/find", 

130 dependencies=[Depends(Auth0Bearer(access_levels=["teacher"]))], 

131 status_code=status.HTTP_200_OK, 

132 description="As a teacher, I can fetch a class by its code", 

133 summary="As a teacher, I can fetch a class by its code", 

134) 

135async def class_find( 

136 request: Request, 

137 class_code: Annotated[ 

138 str, 

139 Path( 

140 min_length=4, 

141 max_length=12, 

142 pattern=r"^[A-Za-z0-9]+$", 

143 description="Alphanumeric class code, 4–12 chars (EI-TC-984).", 

144 ), 

145 ], 

146) -> dict: 

147 """ 

148 Retrieve detailed information about a specific class by its code. 

149 

150 This endpoint returns comprehensive details about a class identified by its unique 

151 class code, including enrollment information, schedule, and other class-specific data. 

152 Only teachers assigned to the class or with appropriate permissions can access the data. 

153 

154 Args: 

155 request (Request): The incoming request object containing: 

156 - JWT token in Authorization header 

157 - Teacher authentication context 

158 - Teacher role and permissions 

159 class_code (str): Unique class code identifier 

160 

161 Returns: 

162 dict: Class details including: 

163 - id (str): Unique class identifier 

164 - name (str): Class name/title 

165 - description (str): Class description/overview 

166 - subject (str): Subject area 

167 - grade_level (int): Target grade level 

168 - teacher (dict): Assigned teacher details 

169 - students (list): Enrolled student information 

170 - schedule (dict): Class meeting schedule 

171 - assignments (list): Associated assignments 

172 - status (str): Current class status 

173 - created_at (datetime): Creation timestamp 

174 - updated_at (datetime): Last update timestamp 

175 

176 Raises: 

177 HTTPException: 

178 - 401: Invalid or missing authentication token 

179 - 403: Insufficient permissions to access class data 

180 - 404: Class not found 

181 - 422: Invalid class code format 

182 - 500: Error retrieving class data 

183 """ 

184 return await teacher_classes_service.class_fetch(request, class_code) 

185 

186 

187@router.get( 

188 "/messages/{class_uuid}/fetch", 

189 dependencies=[Depends(Auth0Bearer(access_levels=["teacher"]))], 

190 status_code=status.HTTP_200_OK, 

191 description="As a teacher, I can fetch the messages for a specific class", 

192 summary="As a teacher, I can fetch the messages for a specific class", 

193) 

194async def messages_fetch( 

195 request: Request, 

196 class_uuid: str 

197 ) -> dict: 

198 """ 

199 Retrieve messages and announcements for a specific class. 

200 

201 This endpoint returns all messages and announcements associated with a class, 

202 including teacher posts, student discussions, and system notifications. Messages 

203 are ordered chronologically and can be filtered by type and date range. 

204 

205 Args: 

206 request (Request): The incoming request object containing: 

207 - JWT token in Authorization header 

208 - Teacher authentication context 

209 - Teacher role and permissions 

210 class_uuid (str): Unique identifier for the class 

211 

212 Returns: 

213 dict: Class messages including: 

214 - messages (list): List of message objects containing: 

215 - id (str): Unique message identifier 

216 - author (dict): Message author details 

217 - content (str): Message text content 

218 - type (str): Message type (announcement/discussion/notification) 

219 - attachments (list): Associated files/links 

220 - created_at (datetime): Post timestamp 

221 - updated_at (datetime): Last edit timestamp 

222 - metadata (dict): 

223 - total_count (int): Total number of messages 

224 - unread_count (int): Number of unread messages 

225 - last_activity (datetime): Most recent message timestamp 

226 

227 Raises: 

228 HTTPException: 

229 - 401: Invalid or missing authentication token 

230 - 403: Insufficient permissions to access class messages 

231 - 404: Class not found 

232 - 422: Invalid class UUID format 

233 - 500: Error retrieving messages 

234 """ 

235 return await teacher_classes_service.class_messages_fetch(request, class_uuid) 

236 

237 

238@router.post( 

239 "/messages/{class_uuid}/create", 

240 dependencies=[Depends(Auth0Bearer(access_levels=["teacher"]))], 

241 status_code=status.HTTP_201_CREATED, 

242 description="As a teacher, I can create a message/announcement for a specific class", 

243 summary="As a teacher, I can create a class announcement", 

244) 

245async def class_message_create( 

246 request: Request, 

247 class_uuid: str, 

248 body: CreateClassMessage, 

249) -> dict: 

250 """ 

251 Create a new announcement for a specific class. 

252 

253 Args: 

254 request (Request): The incoming request object containing teacher context 

255 class_uuid (str): Unique identifier for the class 

256 body (CreateClassMessage): Message content (1-5000 characters) 

257 

258 Returns: 

259 dict: Success detail and message_id 

260 

261 Raises: 

262 HTTPException: 

263 - 400: Invalid class UUID format 

264 - 401: Invalid or missing authentication token 

265 - 404: Class not found 

266 - 422: Validation error (empty or too-long content) 

267 """ 

268 return await teacher_classes_service.class_message_create(request, class_uuid, body) 

269 

270 

271@router.delete( 

272 "/messages/{class_uuid}/{message_id}/delete", 

273 dependencies=[Depends(Auth0Bearer(access_levels=["teacher"]))], 

274 status_code=status.HTTP_200_OK, 

275 description="As a teacher, I can delete a message/announcement from a specific class", 

276 summary="As a teacher, I can delete a class announcement", 

277) 

278async def class_message_delete( 

279 request: Request, 

280 class_uuid: str, 

281 message_id: str, 

282) -> dict: 

283 """ 

284 Delete an announcement from a specific class. 

285 

286 Args: 

287 request (Request): The incoming request object containing teacher context 

288 class_uuid (str): Unique identifier for the class 

289 message_id (str): Unique identifier for the message to delete 

290 

291 Returns: 

292 dict: Success detail 

293 

294 Raises: 

295 HTTPException: 

296 - 400: Invalid ID format 

297 - 401: Invalid or missing authentication token 

298 - 404: Class or message not found 

299 """ 

300 return await teacher_classes_service.class_message_delete(request, class_uuid, message_id) 

301 

302 

303@router.get( 

304 "/gradebook/{class_code:str}/fetch", 

305 dependencies=[Depends(Auth0Bearer(access_levels=["teacher"]))], 

306 status_code=status.HTTP_200_OK, 

307 description="As a teacher, I can fetch the gradebook for a specific class", 

308 summary="As a teacher, I can fetch the gradebook for a specific class", 

309) 

310async def class_gradebook_fetch(request: Request, class_code: ClassCodePath) -> dict: 

311 """ 

312 Retrieve the gradebook for a specific class. 

313 

314 This endpoint returns comprehensive grade information for all students in a class, 

315 including assignment scores, overall grades, and grade trends. The data helps 

316 teachers track student performance and identify areas needing attention. 

317 

318 Args: 

319 request (Request): The incoming request object containing: 

320 - JWT token in Authorization header 

321 - Teacher authentication context 

322 - Teacher role and permissions 

323 class_code (str): class code for the class 

324 

325 Returns: 

326 dict: Gradebook data including: 

327 - students (list): List of student grade records containing: 

328 - student_id (str): Student's unique identifier 

329 - name (str): Student's full name 

330 - overall_grade (float): Current class grade 

331 - assignments (list): Individual assignment grades: 

332 - assignment_id (str): Assignment identifier 

333 - title (str): Assignment name 

334 - score (float): Points earned 

335 - possible (float): Total possible points 

336 - submitted_date (datetime): Submission timestamp 

337 - late (bool): Whether submitted after deadline 

338 - class_stats (dict): 

339 - average_grade (float): Class mean grade 

340 - grade_distribution (dict): Grade breakdown by letter 

341 - assignment_averages (dict): Mean scores per assignment 

342 - missing_work (dict): Incomplete assignment counts 

343 

344 Raises: 

345 HTTPException: 

346 - 401: Invalid or missing authentication token 

347 - 403: Insufficient permissions to access gradebook 

348 - 404: Class not found 

349 - 422: Invalid class UUID format 

350 - 500: Error retrieving gradebook data 

351 """ 

352 return await teacher_classes_service.class_gradebook_fetch(request, class_code) 

353 

354@router.get( 

355 "/roster/{class_uuid}/fetch", 

356 dependencies=[Depends(Auth0Bearer(access_levels=["teacher"]))], 

357 status_code=status.HTTP_200_OK, 

358 description="As a teacher, I can fetch the roster of students for a specific class", 

359 summary="As a teacher, I can fetch the roster of students for a specific class", 

360) 

361async def roster_fetch( 

362 request: Request, 

363 class_uuid: str 

364 ) -> dict: 

365 """ 

366 Retrieve the student roster for a specific class. 

367 

368 This endpoint returns a list of all students enrolled in the specified class, 

369 including their enrollment status and basic profile information. The roster 

370 helps teachers manage class membership and track student participation. 

371 

372 Args: 

373 request (Request): The incoming request object containing: 

374 - JWT token in Authorization header 

375 - Teacher authentication context 

376 - Teacher role and permissions 

377 class_uuid (str): Unique identifier for the class 

378 

379 Returns: 

380 dict: Roster data including: 

381 - students (list): List of enrolled students containing: 

382 - student_id (str): Student's unique identifier 

383 - first_name (str): Student's first name 

384 - last_name (str): Student's last name 

385 - email (str): Student's email address 

386 - status (str): Enrollment status (e.g., "Active", "Pending") 

387 - join_date (datetime): When student joined class 

388 - grade_level (int): Student's current grade level 

389 - roster_stats (dict): 

390 - total_students (int): Number of enrolled students 

391 - active_count (int): Number of active students 

392 - pending_count (int): Number of pending enrollments 

393 - removed_count (int): Number of removed students 

394 

395 Raises: 

396 HTTPException: 

397 - 401: Invalid or missing authentication token 

398 - 403: Insufficient permissions to access roster 

399 - 404: Class not found 

400 - 422: Invalid class UUID format 

401 - 500: Error retrieving roster data 

402 """ 

403 return await teacher_classes_service.class_roster_fetch(request, class_uuid) 

404 

405 

406@router.put( 

407 "/{class_uuid}/update", 

408 dependencies=[Depends(Auth0Bearer(access_levels=["teacher"]))], 

409 status_code=status.HTTP_200_OK, 

410 description="As a teacher, I can update a class details", 

411 summary="As a teacher, I can update a class details", 

412) 

413async def class_update( 

414 updated_class: UpdateClassModel, 

415 request: Request, 

416 class_uuid: str 

417 ) -> dict: 

418 """ 

419 Update details of an existing class. 

420 

421 This endpoint allows teachers to modify class information such as name, description, 

422 schedule, and other configurable settings. Only the teacher assigned to the class 

423 can make these updates. 

424 

425 Args: 

426 updated_class (UpdateClassModel): Updated class details containing: 

427 - name (str): New class name/title 

428 - description (str): New class description 

429 - subject (str): Updated subject area 

430 - grade_level (int): Modified target grade level 

431 - schedule (dict): Updated meeting schedule 

432 - max_students (int): New maximum enrollment capacity 

433 - status (str): New class status (e.g. "active", "archived") 

434 - settings (dict): Modified class configuration 

435 request (Request): The incoming request object containing: 

436 - JWT token in Authorization header 

437 - Teacher authentication context 

438 - Teacher role and permissions 

439 class_uuid (str): Unique identifier for the class to update 

440 

441 Returns: 

442 dict: Updated class details including: 

443 - id (str): Class unique identifier 

444 - name (str): Updated class name 

445 - description (str): Updated description 

446 - subject (str): Updated subject 

447 - grade_level (int): Updated grade level 

448 - schedule (dict): Updated schedule details 

449 - status (str): Updated class status 

450 - teacher (dict): Assigned teacher information 

451 - updated_at (datetime): Last modification timestamp 

452 

453 Raises: 

454 HTTPException: 

455 - 401: Invalid or missing authentication token 

456 - 403: Teacher does not have permission to update this class 

457 - 404: Class not found 

458 - 422: Invalid update data provided 

459 - 500: Error updating class 

460 """ 

461 return await teacher_classes_service.class_update(updated_class, request, class_uuid) 

462 

463 

464@router.delete( 

465 "/{class_uuid}/delete", 

466 dependencies=[Depends(Auth0Bearer(access_levels=["teacher"]))], 

467 status_code=status.HTTP_200_OK, 

468 description="As a teacher, I can delete a class", 

469 summary="As a teacher, I can delete a class", 

470) 

471async def class_delete( 

472 request: Request, 

473 class_uuid: str 

474 ) -> dict: 

475 """ 

476 Delete a specific class from the system. 

477 

478 This endpoint allows teachers to permanently remove a class they created. Only the teacher 

479 who owns the class can delete it. Deleting a class will remove all associated data including 

480 student enrollments, assignments, and class materials. 

481 

482 Args: 

483 request (Request): The incoming request object containing: 

484 - JWT token in Authorization header 

485 - Teacher authentication context 

486 - Teacher role and permissions 

487 class_uuid (str): Unique identifier of the class to delete 

488 

489 Returns: 

490 dict: Deletion confirmation containing: 

491 - detail (str): Success message 

492 - class_id (str): ID of the deleted class 

493 

494 Raises: 

495 HTTPException: 

496 - 401: Invalid or missing authentication token 

497 - 403: Teacher does not have permission to delete this class 

498 - 404: Class not found 

499 - 500: Error deleting class 

500 """ 

501 return await teacher_classes_service.class_delete(request, class_uuid) 

502 

503 

504@router.post( 

505 "/{class_uuid}/photo/add", 

506 dependencies=[Depends(Auth0Bearer(access_levels=["teacher"]))], 

507 status_code=status.HTTP_200_OK, 

508 description="As a teacher, I can upload a cover photo for a class card", 

509 summary="As a teacher, I can upload a class cover photo", 

510) 

511async def class_photo_add( 

512 request: Request, 

513 class_uuid: str, 

514 file: UploadFile = File(...), 

515) -> dict: 

516 """ 

517 Upload a cover photo for a class that doesn't have one yet. 

518 

519 Args: 

520 request (Request): The incoming request object containing teacher context 

521 class_uuid (str): Unique identifier of the class 

522 file (UploadFile): Image file to upload (JPG/PNG, max 10MB) 

523 

524 Returns: 

525 dict: {"detail": str, "updated_class": ClassModel} with the new cover 

526 photo URL. 

527 

528 Raises: 

529 HTTPException: 

530 - 400: Invalid class ID, or the class already has a cover photo 

531 - 401: Invalid or missing authentication token 

532 - 403: Teacher does not own this class 

533 - 404: Class not found 

534 - 413/415: File too large or unsupported type 

535 """ 

536 return await teacher_classes_service.class_photo_add(request, class_uuid, file) 

537 

538 

539@router.patch( 

540 "/{class_uuid}/photo/update", 

541 dependencies=[Depends(Auth0Bearer(access_levels=["teacher"]))], 

542 status_code=status.HTTP_200_OK, 

543 description="As a teacher, I can replace a class card's cover photo", 

544 summary="As a teacher, I can update a class cover photo", 

545) 

546async def class_photo_update( 

547 request: Request, 

548 class_uuid: str, 

549 file: UploadFile = File(...), 

550) -> dict: 

551 """ 

552 Replace an existing class cover photo. 

553 

554 Args: 

555 request (Request): The incoming request object containing teacher context 

556 class_uuid (str): Unique identifier of the class 

557 file (UploadFile): Image file to upload (JPG/PNG, max 10MB) 

558 

559 Returns: 

560 dict: {"detail": str, "updated_class": ClassModel} with the replaced 

561 cover photo URL. 

562 

563 Raises: 

564 HTTPException: 

565 - 400: Invalid class ID, or the class has no cover photo to update 

566 - 401: Invalid or missing authentication token 

567 - 403: Teacher does not own this class 

568 - 404: Class not found 

569 - 413/415: File too large or unsupported type 

570 """ 

571 return await teacher_classes_service.class_photo_update(request, class_uuid, file) 

572 

573 

574@router.delete( 

575 "/{class_uuid}/photo/delete", 

576 dependencies=[Depends(Auth0Bearer(access_levels=["teacher"]))], 

577 status_code=status.HTTP_200_OK, 

578 description="As a teacher, I can remove a class card's cover photo", 

579 summary="As a teacher, I can delete a class cover photo", 

580) 

581async def class_photo_delete(request: Request, class_uuid: str) -> dict: 

582 """ 

583 Remove a class's cover photo and delete it from storage. 

584 

585 Args: 

586 request (Request): The incoming request object containing teacher context 

587 class_uuid (str): Unique identifier of the class 

588 

589 Returns: 

590 dict: {"detail": str, "updated_class": ClassModel} with class_photo 

591 cleared. 

592 

593 Raises: 

594 HTTPException: 

595 - 400: Invalid class ID 

596 - 401: Invalid or missing authentication token 

597 - 403: Teacher does not own this class 

598 - 404: Class not found 

599 """ 

600 return await teacher_classes_service.class_photo_delete(request, class_uuid) 

601 

602 

603@router.post( 

604 "/{class_uuid}/restore", 

605 dependencies=[Depends(Auth0Bearer(access_levels=["teacher"]))], 

606 status_code=status.HTTP_200_OK, 

607 description="As a teacher, I can restore a soft-deleted (archived) class", 

608 summary="As a teacher, I can restore a soft-deleted class", 

609) 

610async def class_restore( 

611 request: Request, 

612 class_uuid: str, 

613) -> dict: 

614 """ 

615 Restore a soft-deleted class so it becomes visible to user-facing 

616 queries again. The class's `class_code` is unchanged — it was kept 

617 reserved by `generate_unique_code` while the class was soft-deleted. 

618 

619 Raises: 

620 HTTPException: 

621 - 400: Class is not soft-deleted (already live). 

622 - 401: Invalid or missing authentication token. 

623 - 403: Teacher does not own this class. 

624 - 404: Class not found. 

625 - 500: Error restoring class. 

626 """ 

627 return await teacher_classes_service.class_restore(request, class_uuid) 

628 

629 

630@router.patch( 

631 "/{class_uuid:str}/{student_id:str}/student_accept", 

632 dependencies=[Depends(Auth0Bearer(access_levels=["teacher"]))], 

633 status_code=status.HTTP_200_OK, 

634 description="As a teacher, I can accept a student's request to join a class", 

635 summary="As a teacher, I can accept a student's request to join a class", 

636) 

637async def accept_student(request: Request, class_uuid: str, student_id: str): 

638 """ 

639 Accept a pending student's request to join a class. 

640 

641 Args: 

642 request (Request): The incoming request object containing teacher context 

643 class_uuid (str): Unique identifier of the class 

644 payload (UpdateStudentStatus): Contains student_id of the student to accept 

645 

646 Returns: 

647 dict: Acceptance confirmation message 

648 Example: {"detail": "Successfully accepted student to the class"} 

649 

650 Raises: 

651 HTTPException: 

652 - 404: If class not found or student not in class 

653 - 400: If no students in class or invalid class ID 

654 - 500: For unexpected server errors 

655 InvalidStudentRequest: If student is already enrolled 

656 

657 Note: 

658 Only students with "Pending" status can be accepted. The method updates 

659 their status to "Enrolled" upon successful acceptance. 

660 """ 

661 return await teacher_classes_service.student_accepted(request, class_uuid, student_id) 

662 

663 

664@router.delete( 

665 "/{class_uuid}/{student_id}/student_remove", 

666 dependencies=[Depends(Auth0Bearer(access_levels=["teacher"]))], 

667 status_code=status.HTTP_200_OK, 

668 description="As a teacher, I can remove a student from a class", 

669 summary="As a teacher, I can remove a student from a class", 

670) 

671async def remove_student(request: Request, class_uuid: str, student_id: str): 

672 """ 

673 Remove a student from a class. 

674 

675 Args: 

676 request (Request): The incoming request object containing teacher context 

677 class_uuid (str): Unique identifier of the class 

678 student_id (str): Identifier of the student to remove 

679 

680 Returns: 

681 dict: Removal confirmation and updated class roster 

682 """ 

683 return await teacher_classes_service.student_remove(request, class_uuid, student_id) 

684 

685 

686 

687@router.patch( 

688 "/{class_uuid}/{student_id}/leave_approved", 

689 dependencies=[Depends(Auth0Bearer(access_levels=["teacher"]))], 

690 status_code=status.HTTP_200_OK, 

691 description="As a teacher, I can accept a student's request to leave a class", 

692 summary="As a teacher, I can accept a student's request to leave a class", 

693 ) 

694async def leave_approved( 

695 request: Request, class_uuid: str, student_id: str, leave_request_data: LeaveRequestData 

696): 

697 """ 

698 Process a student's request to leave a class. 

699 

700 Args: 

701 request (Request): The incoming request object containing teacher context 

702 class_uuid (str): Unique identifier of the class 

703 leave_request_data (LeaveRequestData): Data containing leave request details 

704 and approval status 

705 

706 Returns: 

707 dict: Leave request processing confirmation and updated class roster 

708 """ 

709 return await teacher_classes_service.leave_approved( 

710 request, class_uuid, student_id, leave_request_data 

711 ) 

712 

713@router.get( 

714 "/assignments/{class_uuid}/fetch", 

715 dependencies=[Depends(Auth0Bearer(access_levels=["teacher"]))], 

716 status_code=status.HTTP_200_OK, 

717 description="As a teacher, I can fetch the assignments for a specific class", 

718 summary="As a teacher, I can fetch the assignments for a specific class", 

719) 

720async def assignments_fetch(request: Request, class_uuid: str) -> dict: 

721 """ 

722 Retrieve all assignments for a specific class. 

723 

724 This endpoint returns a list of all assignments associated with the specified class. 

725 Only teachers assigned to the class can access its assignments. 

726 

727 Args: 

728 request (Request): The incoming request object containing: 

729 - JWT token in Authorization header 

730 - Teacher authentication context 

731 class_uuid (str): Unique identifier for the class 

732 

733 Returns: 

734 list[dict]: List of assignments, each containing: 

735 - _id (ObjectId): Unique assignment identifier 

736 - title (str): Assignment title 

737 - description (str): Assignment description 

738 - semester (str): Academic semester 

739 - class_id (str): Associated class identifier 

740 - teacher_id (str): Teacher who created the assignment 

741 - date_open (datetime): Assignment start date 

742 - date_close (datetime): Assignment due date 

743 - status (str): Assignment status (e.g., "Assigned") 

744 - total_submissions (int): Number of student submissions 

745 - question_ids (list): List of associated question IDs 

746 - submission_ids (list): List of student submission IDs 

747 - settings (dict): Assignment configuration settings 

748 - created_at (datetime): Creation timestamp 

749 - updated_at (datetime): Last update timestamp 

750 

751 Raises: 

752 HTTPException: 

753 - 401: Invalid or missing authentication token 

754 - 403: Teacher not authorized to access this class 

755 - 404: Class not found 

756 - 500: Error retrieving assignments 

757 """ 

758 return await teacher_classes_service.class_assignments_fetch(request, class_uuid)