File size: 7,620 Bytes
92c8a69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Param,
  Body,
  Query,
  UseGuards,
  ParseIntPipe,
  Request,
} from '@nestjs/common';
import {
  ApiTags,
  ApiBearerAuth,
  ApiOperation,
  ApiResponse,
  ApiParam,
  ApiBody,
  ApiQuery,
} from '@nestjs/swagger';
import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../../auth/guards/roles.guard';
import { Roles } from '../../../common/decorators/roles.decorator';
import { RoleName } from '../../auth/entities/role.entity';
import { StudyGroupsService } from '../services/study-groups.service';
import { CreateStudyGroupDto } from '../dto/create-study-group.dto';
import { UpdateStudyGroupDto } from '../dto/update-study-group.dto';

@ApiTags('๐Ÿ“š Study Groups')
@ApiBearerAuth('JWT-auth')
@Controller('api/study-groups')
@UseGuards(JwtAuthGuard, RolesGuard)
export class StudyGroupsController {
  constructor(private readonly studyGroupsService: StudyGroupsService) {}

  @Get()
  @Roles(RoleName.STUDENT, RoleName.INSTRUCTOR, RoleName.TA, RoleName.ADMIN, RoleName.IT_ADMIN)
  @ApiOperation({
    summary: 'List all study groups',
    description:
      'Retrieves all study groups. Optionally filter by courseId. ' +
      'Access roles: ALL. Uses tables: `study_groups`.',
  })
  @ApiQuery({ name: 'courseId', required: false, type: Number, description: 'Filter by course ID' })
  @ApiResponse({ status: 200, description: 'Study groups returned' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  async findAll(@Query('courseId') courseId?: number) {
    return this.studyGroupsService.findAll(courseId ? +courseId : undefined);
  }

  @Get('my')
  @Roles(RoleName.STUDENT, RoleName.INSTRUCTOR, RoleName.TA, RoleName.ADMIN, RoleName.IT_ADMIN)
  @ApiOperation({
    summary: 'Get my study groups',
    description:
      'Retrieves all study groups the current user is a member of. ' +
      'Access roles: ALL. Uses tables: `study_group_members`, `study_groups`.',
  })
  @ApiResponse({ status: 200, description: 'User study groups returned' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  async findMyGroups(@Request() req) {
    return this.studyGroupsService.findMyGroups(req.user.userId);
  }

  @Get(':id')
  @Roles(RoleName.STUDENT, RoleName.INSTRUCTOR, RoleName.TA, RoleName.ADMIN, RoleName.IT_ADMIN)
  @ApiOperation({
    summary: 'Get study group by ID',
    description:
      'Retrieves details of a specific study group. ' +
      'Access roles: ALL. Uses table: `study_groups`.',
  })
  @ApiParam({ name: 'id', type: Number, description: 'Study group ID' })
  @ApiResponse({ status: 200, description: 'Study group details returned' })
  @ApiResponse({ status: 404, description: 'Study group not found' })
  async findById(@Param('id', ParseIntPipe) id: number) {
    return this.studyGroupsService.findById(id);
  }

  @Post()
  @Roles(RoleName.STUDENT, RoleName.INSTRUCTOR, RoleName.TA, RoleName.ADMIN, RoleName.IT_ADMIN)
  @ApiOperation({
    summary: 'Create a study group',
    description:
      'Creates a new study group and automatically adds the creator as the first member with "creator" role. ' +
      'Access roles: ALL. Uses tables: `study_groups`, `study_group_members`.',
  })
  @ApiBody({ type: CreateStudyGroupDto })
  @ApiResponse({ status: 201, description: 'Study group created' })
  @ApiResponse({ status: 400, description: 'Validation error' })
  async create(@Body() dto: CreateStudyGroupDto, @Request() req) {
    return this.studyGroupsService.createGroup(dto, req.user.userId);
  }

  @Put(':id')
  @Roles(RoleName.STUDENT, RoleName.INSTRUCTOR, RoleName.TA, RoleName.ADMIN, RoleName.IT_ADMIN)
  @ApiOperation({
    summary: 'Update a study group',
    description:
      'Updates an existing study group. Only the group creator can update. ' +
      'Access roles: OWNER. Uses table: `study_groups`.',
  })
  @ApiParam({ name: 'id', type: Number, description: 'Study group ID' })
  @ApiBody({ type: UpdateStudyGroupDto })
  @ApiResponse({ status: 200, description: 'Study group updated' })
  @ApiResponse({ status: 403, description: 'Forbidden โ€“ not the creator' })
  @ApiResponse({ status: 404, description: 'Study group not found' })
  async update(
    @Param('id', ParseIntPipe) id: number,
    @Body() dto: UpdateStudyGroupDto,
    @Request() req,
  ) {
    return this.studyGroupsService.updateGroup(id, dto, req.user.userId);
  }

  @Delete(':id')
  @Roles(RoleName.STUDENT, RoleName.INSTRUCTOR, RoleName.TA, RoleName.ADMIN, RoleName.IT_ADMIN)
  @ApiOperation({
    summary: 'Delete a study group',
    description:
      'Deletes a study group and all its memberships. Only the group creator or admins can delete. ' +
      'Access roles: OWNER, ADMIN. Uses tables: `study_groups`, `study_group_members`.',
  })
  @ApiParam({ name: 'id', type: Number, description: 'Study group ID' })
  @ApiResponse({ status: 200, description: 'Study group deleted' })
  @ApiResponse({ status: 403, description: 'Forbidden โ€“ not the creator or admin' })
  @ApiResponse({ status: 404, description: 'Study group not found' })
  async delete(@Param('id', ParseIntPipe) id: number, @Request() req) {
    const userRoles = req.user.roles || [];
    return this.studyGroupsService.deleteGroup(id, req.user.userId, userRoles);
  }

  @Post(':id/join')
  @Roles(RoleName.STUDENT, RoleName.INSTRUCTOR, RoleName.TA, RoleName.ADMIN, RoleName.IT_ADMIN)
  @ApiOperation({
    summary: 'Join a study group',
    description:
      'Joins the current user to a study group. Checks if: group is active, not full, user not already a member. ' +
      'Access roles: ALL. Uses tables: `study_groups`, `study_group_members`.',
  })
  @ApiParam({ name: 'id', type: Number, description: 'Study group ID' })
  @ApiResponse({ status: 201, description: 'Joined study group successfully' })
  @ApiResponse({ status: 400, description: 'Already a member or group is full' })
  @ApiResponse({ status: 404, description: 'Study group not found' })
  async join(@Param('id', ParseIntPipe) id: number, @Request() req) {
    return this.studyGroupsService.joinGroup(id, req.user.userId);
  }

  @Delete(':id/leave')
  @Roles(RoleName.STUDENT, RoleName.INSTRUCTOR, RoleName.TA, RoleName.ADMIN, RoleName.IT_ADMIN)
  @ApiOperation({
    summary: 'Leave a study group',
    description:
      'Removes the current user from a study group. The group creator cannot leave (must delete the group instead). ' +
      'Access roles: ALL. Uses tables: `study_groups`, `study_group_members`.',
  })
  @ApiParam({ name: 'id', type: Number, description: 'Study group ID' })
  @ApiResponse({ status: 200, description: 'Left study group successfully' })
  @ApiResponse({ status: 400, description: 'Not a member or is creator' })
  @ApiResponse({ status: 404, description: 'Study group not found' })
  async leave(@Param('id', ParseIntPipe) id: number, @Request() req) {
    return this.studyGroupsService.leaveGroup(id, req.user.userId);
  }

  @Get(':id/members')
  @Roles(RoleName.STUDENT, RoleName.INSTRUCTOR, RoleName.TA, RoleName.ADMIN, RoleName.IT_ADMIN)
  @ApiOperation({
    summary: 'List study group members',
    description:
      'Retrieves all members of a specific study group. ' +
      'Access roles: ALL. Uses tables: `study_group_members`.',
  })
  @ApiParam({ name: 'id', type: Number, description: 'Study group ID' })
  @ApiResponse({ status: 200, description: 'Members returned' })
  @ApiResponse({ status: 404, description: 'Study group not found' })
  async getMembers(@Param('id', ParseIntPipe) id: number) {
    return this.studyGroupsService.getMembers(id);
  }
}