Spaces:
Sleeping
Sleeping
| import { | |
| Controller, | |
| Get, | |
| Post, | |
| Put, | |
| Delete, | |
| Patch, | |
| Body, | |
| Param, | |
| Req, | |
| UseGuards, | |
| ParseIntPipe, | |
| HttpCode, | |
| HttpStatus, | |
| } from '@nestjs/common'; | |
| import { | |
| ApiTags, | |
| ApiOperation, | |
| ApiParam, | |
| ApiBody, | |
| ApiResponse, | |
| ApiBearerAuth, | |
| } from '@nestjs/swagger'; | |
| import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard'; | |
| import { RolesGuard } from '../../auth/guards/roles.guard'; | |
| import { Roles } from '../../auth/roles.decorator'; | |
| import { RoleName } from '../../auth/entities/role.entity'; | |
| import { CourseStructureService } from '../services'; | |
| import { | |
| CreateStructureDto, | |
| UpdateStructureDto, | |
| ReorderStructureDto, | |
| } from '../dto'; | |
| ('🏗️ Course Structure') | |
| ('JWT-auth') | |
| ('api/courses/:courseId/structure') | |
| (JwtAuthGuard, RolesGuard) | |
| export class CourseStructureController { | |
| constructor(private readonly structureService: CourseStructureService) {} | |
| () | |
| ({ | |
| summary: 'Get course structure', | |
| description: ` | |
| ## Get Course Content Structure | |
| Returns the course's content organization (lectures, sections, labs) grouped by week. | |
| ### Access Control | |
| - **Authentication Required**: ✅ Yes (Bearer Token) | |
| - **Roles**: ALL | |
| ### Response Structure | |
| - \`data\`: Flat list of all structure items | |
| - \`byWeek\`: Items grouped by week number for easy display | |
| ### Use Cases | |
| - Building course syllabus view | |
| - Navigation sidebar | |
| - Progress tracking | |
| `, | |
| }) | |
| ({ name: 'courseId', description: 'Course ID', type: Number, example: 1 }) | |
| ({ status: 200, description: 'Course structure retrieved' }) | |
| ({ status: 401, description: 'Unauthorized' }) | |
| async findAll(('courseId', ParseIntPipe) courseId: number) { | |
| return this.structureService.findAll(courseId); | |
| } | |
| (':id') | |
| ({ | |
| summary: 'Get structure item by ID', | |
| description: ` | |
| ## Get Structure Item Details | |
| Returns detailed information about a specific structure item. | |
| ### Access Control | |
| - **Authentication Required**: ✅ Yes (Bearer Token) | |
| - **Roles**: ALL | |
| `, | |
| }) | |
| ({ name: 'courseId', description: 'Course ID', type: Number, example: 1 }) | |
| ({ name: 'id', description: 'Structure item ID', type: Number, example: 1 }) | |
| ({ status: 200, description: 'Structure item details' }) | |
| ({ status: 404, description: 'Structure item not found' }) | |
| async findById( | |
| ('courseId', ParseIntPipe) courseId: number, | |
| ('id', ParseIntPipe) id: number, | |
| ) { | |
| return this.structureService.findById(id); | |
| } | |
| () | |
| (RoleName.INSTRUCTOR, RoleName.ADMIN, RoleName.IT_ADMIN) | |
| (HttpStatus.CREATED) | |
| ({ | |
| summary: 'Create structure item', | |
| description: ` | |
| ## Create Course Structure Item | |
| Adds a new content organization item (lecture, section, lab) to the course. | |
| ### Access Control | |
| - **Authentication Required**: ✅ Yes (Bearer Token) | |
| - **Roles**: INSTRUCTOR, ADMIN only (TAs cannot modify structure) | |
| ### Organization Types | |
| - \`lecture\`: Main lecture content | |
| - \`section\`: Discussion or tutorial section | |
| - \`lab\`: Hands-on lab session | |
| - \`tutorial\`: Tutorial session | |
| ### Ordering | |
| - Items are automatically ordered within their week | |
| - Use \`orderIndex\` to specify custom order | |
| - Use PATCH /reorder to reorder multiple items | |
| `, | |
| }) | |
| ({ name: 'courseId', description: 'Course ID', type: Number, example: 1 }) | |
| ({ type: CreateStructureDto }) | |
| ({ status: 201, description: 'Structure item created' }) | |
| ({ status: 400, description: 'Invalid input data' }) | |
| ({ status: 403, description: 'Forbidden' }) | |
| async create( | |
| ('courseId', ParseIntPipe) courseId: number, | |
| () dto: CreateStructureDto, | |
| () req: any, | |
| ) { | |
| const userId = req.user.userId || req.user.id; | |
| const roles = this.extractRoles(req.user); | |
| return this.structureService.create(courseId, dto, userId, roles); | |
| } | |
| (':id') | |
| (RoleName.INSTRUCTOR, RoleName.ADMIN, RoleName.IT_ADMIN) | |
| ({ | |
| summary: 'Update structure item', | |
| description: ` | |
| ## Update Structure Item | |
| Updates an existing structure item. | |
| ### Access Control | |
| - **Authentication Required**: ✅ Yes (Bearer Token) | |
| - **Roles**: INSTRUCTOR, ADMIN only | |
| `, | |
| }) | |
| ({ name: 'courseId', description: 'Course ID', type: Number, example: 1 }) | |
| ({ name: 'id', description: 'Structure item ID', type: Number, example: 1 }) | |
| ({ type: UpdateStructureDto }) | |
| ({ status: 200, description: 'Structure item updated' }) | |
| ({ status: 404, description: 'Structure item not found' }) | |
| ({ status: 403, description: 'Forbidden' }) | |
| async update( | |
| ('courseId', ParseIntPipe) courseId: number, | |
| ('id', ParseIntPipe) id: number, | |
| () dto: UpdateStructureDto, | |
| () req: any, | |
| ) { | |
| const userId = req.user.userId || req.user.id; | |
| const roles = this.extractRoles(req.user); | |
| return this.structureService.update(id, dto, userId, roles); | |
| } | |
| (':id') | |
| (RoleName.INSTRUCTOR, RoleName.ADMIN, RoleName.IT_ADMIN) | |
| (HttpStatus.OK) | |
| ({ | |
| summary: 'Delete structure item', | |
| description: ` | |
| ## Delete Structure Item | |
| Removes a structure item from the course. | |
| ### Access Control | |
| - **Authentication Required**: ✅ Yes (Bearer Token) | |
| - **Roles**: INSTRUCTOR, ADMIN only | |
| ### Note | |
| Deleting a structure item does NOT delete associated materials. | |
| `, | |
| }) | |
| ({ name: 'courseId', description: 'Course ID', type: Number, example: 1 }) | |
| ({ name: 'id', description: 'Structure item ID', type: Number, example: 1 }) | |
| ({ status: 200, description: 'Structure item deleted' }) | |
| ({ status: 404, description: 'Structure item not found' }) | |
| ({ status: 403, description: 'Forbidden' }) | |
| async delete( | |
| ('courseId', ParseIntPipe) courseId: number, | |
| ('id', ParseIntPipe) id: number, | |
| () req: any, | |
| ) { | |
| const userId = req.user.userId || req.user.id; | |
| const roles = this.extractRoles(req.user); | |
| return this.structureService.delete(id, userId, roles); | |
| } | |
| ('reorder') | |
| (RoleName.INSTRUCTOR, RoleName.ADMIN, RoleName.IT_ADMIN) | |
| ({ | |
| summary: 'Reorder structure items', | |
| description: ` | |
| ## Reorder Structure Items | |
| Changes the order of structure items within a course. | |
| ### Access Control | |
| - **Authentication Required**: ✅ Yes (Bearer Token) | |
| - **Roles**: INSTRUCTOR, ADMIN only | |
| ### Request Body | |
| Provide array of structure item IDs in the desired new order. | |
| ### Example | |
| \`\`\`json | |
| { | |
| "orderIds": [3, 1, 2, 4] | |
| } | |
| \`\`\` | |
| This would reorder items so that: | |
| - ID 3 is first (orderIndex: 0) | |
| - ID 1 is second (orderIndex: 1) | |
| - ID 2 is third (orderIndex: 2) | |
| - ID 4 is fourth (orderIndex: 3) | |
| `, | |
| }) | |
| ({ name: 'courseId', description: 'Course ID', type: Number, example: 1 }) | |
| ({ type: ReorderStructureDto }) | |
| ({ status: 200, description: 'Items reordered successfully' }) | |
| ({ status: 400, description: 'Invalid input data' }) | |
| ({ status: 403, description: 'Forbidden' }) | |
| ({ status: 404, description: 'Some items not found' }) | |
| async reorder( | |
| ('courseId', ParseIntPipe) courseId: number, | |
| () dto: ReorderStructureDto, | |
| () req: any, | |
| ) { | |
| const userId = req.user.userId || req.user.id; | |
| const roles = this.extractRoles(req.user); | |
| return this.structureService.reorder(courseId, dto, userId, roles); | |
| } | |
| private extractRoles(user: any): string[] { | |
| if (Array.isArray(user.roles)) { | |
| return user.roles.map((r: any) => (typeof r === 'string' ? r : r.name || r.roleName)); | |
| } | |
| return []; | |
| } | |
| } | |