Spaces:
Sleeping
Sleeping
| import { | |
| Controller, | |
| Get, | |
| Post, | |
| Put, | |
| Body, | |
| Param, | |
| Query, | |
| 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 { CommunitiesService } from '../services/communities.service'; | |
| import { CommunityPostsService } from '../services/community-posts.service'; | |
| import { CommunityTagsService } from '../services/community-tags.service'; | |
| import { | |
| CreateCommunityDto, | |
| UpdateCommunityDto, | |
| CommunityQueryDto, | |
| CreatePostDto, | |
| PostQueryDto, | |
| CreateTagDto, | |
| } from '../dto'; | |
| ('🏘️ Communities') | |
| ('JWT-auth') | |
| ('api/community') | |
| (JwtAuthGuard, RolesGuard) | |
| export class CommunitiesController { | |
| constructor( | |
| private readonly communitiesService: CommunitiesService, | |
| private readonly postsService: CommunityPostsService, | |
| private readonly tagsService: CommunityTagsService, | |
| ) {} | |
| // ============== COMMUNITY CRUD ============== | |
| ('communities') | |
| ({ | |
| summary: 'List communities', | |
| description: 'List all communities the user has access to. Global communities are visible to all. Department communities are filtered by enrollment.', | |
| }) | |
| ({ status: 200, description: 'Paginated list of communities' }) | |
| async findAllCommunities(() query: CommunityQueryDto, () req: any) { | |
| const userId = req.user.userId || req.user.id; | |
| const roles = this.extractRoles(req.user); | |
| return this.communitiesService.findAll(query, userId, roles); | |
| } | |
| ('communities') | |
| (HttpStatus.CREATED) | |
| (RoleName.ADMIN, RoleName.IT_ADMIN, RoleName.DEPARTMENT_HEAD, RoleName.INSTRUCTOR) | |
| ({ | |
| summary: 'Create a community', | |
| description: 'Create a new global or department community. Admin/Instructor/Department Head only.', | |
| }) | |
| ({ type: CreateCommunityDto }) | |
| ({ status: 201, description: 'Community created' }) | |
| async createCommunity(() dto: CreateCommunityDto, () req: any) { | |
| const userId = req.user.userId || req.user.id; | |
| return this.communitiesService.create(dto, userId); | |
| } | |
| ('communities/:communityId') | |
| ({ summary: 'Get community details' }) | |
| ({ name: 'communityId', description: 'Community ID' }) | |
| ({ status: 200, description: 'Community details' }) | |
| async getCommunity(('communityId', ParseIntPipe) communityId: number, () req: any) { | |
| const userId = req.user.userId || req.user.id; | |
| const roles = this.extractRoles(req.user); | |
| return this.communitiesService.checkAccess(communityId, userId, roles); | |
| } | |
| ('communities/:communityId') | |
| (RoleName.ADMIN, RoleName.IT_ADMIN, RoleName.DEPARTMENT_HEAD, RoleName.INSTRUCTOR) | |
| ({ summary: 'Update a community' }) | |
| ({ name: 'communityId', description: 'Community ID' }) | |
| ({ type: UpdateCommunityDto }) | |
| async updateCommunity( | |
| ('communityId', ParseIntPipe) communityId: number, | |
| () dto: UpdateCommunityDto, | |
| () req: any, | |
| ) { | |
| const userId = req.user.userId || req.user.id; | |
| const roles = this.extractRoles(req.user); | |
| return this.communitiesService.update(communityId, dto, userId, roles); | |
| } | |
| // ============== COMMUNITY POSTS ============== | |
| ('communities/:communityId/posts') | |
| ({ | |
| summary: 'List posts in a community', | |
| description: 'Get paginated posts from a specific community. Access is validated.', | |
| }) | |
| ({ name: 'communityId', description: 'Community ID' }) | |
| async getCommunityPosts( | |
| ('communityId', ParseIntPipe) communityId: number, | |
| () query: PostQueryDto, | |
| () req: any, | |
| ) { | |
| const userId = req.user.userId || req.user.id; | |
| const roles = this.extractRoles(req.user); | |
| // Validate access | |
| await this.communitiesService.checkAccess(communityId, userId, roles); | |
| // Override communityId in query | |
| query.communityId = communityId; | |
| return this.postsService.findAll(query); | |
| } | |
| ('communities/:communityId/posts') | |
| (HttpStatus.CREATED) | |
| ({ | |
| summary: 'Create a post in a community', | |
| description: 'Create a new post in a specific community. Access is validated.', | |
| }) | |
| ({ name: 'communityId', description: 'Community ID' }) | |
| ({ type: CreatePostDto }) | |
| async createCommunityPost( | |
| ('communityId', ParseIntPipe) communityId: number, | |
| () dto: CreatePostDto, | |
| () req: any, | |
| ) { | |
| const userId = req.user.userId || req.user.id; | |
| const roles = this.extractRoles(req.user); | |
| // Validate access | |
| await this.communitiesService.checkAccess(communityId, userId, roles); | |
| // Override communityId | |
| dto.communityId = communityId; | |
| return this.postsService.create(dto, userId); | |
| } | |
| // ============== CONVENIENCE ROUTES ============== | |
| ('global') | |
| ({ | |
| summary: 'Get global community posts', | |
| description: 'Shortcut to list posts from the global community (community_id = 1).', | |
| }) | |
| async getGlobalPosts(() query: PostQueryDto) { | |
| query.communityId = 1; // Global community is always ID 1 | |
| return this.postsService.findAll(query); | |
| } | |
| ('global/posts') | |
| (HttpStatus.CREATED) | |
| ({ | |
| summary: 'Create a post in global community', | |
| description: 'Shortcut to create a post in the global community.', | |
| }) | |
| ({ type: CreatePostDto }) | |
| async createGlobalPost(() dto: CreatePostDto, () req: any) { | |
| const userId = req.user.userId || req.user.id; | |
| dto.communityId = 1; | |
| return this.postsService.create(dto, userId); | |
| } | |
| ('department/:departmentId') | |
| ({ | |
| summary: 'List department communities', | |
| description: 'List all communities for a specific department. Access is validated by enrollment.', | |
| }) | |
| ({ name: 'departmentId', description: 'Department ID' }) | |
| async getDepartmentCommunities( | |
| ('departmentId', ParseIntPipe) departmentId: number, | |
| () query: CommunityQueryDto, | |
| () req: any, | |
| ) { | |
| const userId = req.user.userId || req.user.id; | |
| const roles = this.extractRoles(req.user); | |
| query.departmentId = departmentId; | |
| return this.communitiesService.findAll(query, userId, roles); | |
| } | |
| ('my-departments') | |
| ({ | |
| summary: 'Get my accessible departments', | |
| description: 'Returns department IDs the user has access to based on enrollment.', | |
| }) | |
| async getMyDepartments(() req: any) { | |
| const userId = req.user.userId || req.user.id; | |
| const departmentIds = await this.communitiesService.getUserDepartmentIds(userId); | |
| return { departmentIds }; | |
| } | |
| // ============== TAGS ============== | |
| ('tags') | |
| ({ summary: 'List all tags' }) | |
| async getAllTags() { | |
| return this.tagsService.findAll(); | |
| } | |
| ('tags') | |
| (HttpStatus.CREATED) | |
| (RoleName.INSTRUCTOR, RoleName.ADMIN, RoleName.IT_ADMIN, RoleName.TA) | |
| ({ | |
| summary: 'Create a tag', | |
| description: 'Create a new tag. Instructor/Admin/TA only.', | |
| }) | |
| ({ type: CreateTagDto }) | |
| async createTag(() dto: CreateTagDto) { | |
| return this.tagsService.create(dto); | |
| } | |
| // ============== HELPER ============== | |
| private extractRoles(user: any): string[] { | |
| if (!user.roles) return []; | |
| return user.roles.map((r: any) => r.roleName || r.name || r); | |
| } | |
| } | |