• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

classconnect-grupo3 / courses-service / 15914402693

26 Jun 2025 11:12PM UTC coverage: 81.843% (-5.9%) from 87.722%
15914402693

Pull #49

github

web-flow
Merge pull request #48 from classconnect-grupo3/notification-messages-and-testing

Notification messages and testing
Pull Request #49: Final merge (thank you for the ride)

1542 of 2153 new or added lines in 24 files covered. (71.62%)

16 existing lines in 5 files now uncovered.

4548 of 5557 relevant lines covered (81.84%)

0.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.25
/src/controller/courses_controller.go
1
package controller
2

3
import (
4
        "fmt"
5
        "log/slog"
6
        "net/http"
7
        "slices"
8

9
        "courses-service/src/ai"
10
        "courses-service/src/model"
11
        "courses-service/src/queues"
12
        "courses-service/src/schemas"
13
        "courses-service/src/service"
14

15
        "github.com/gin-gonic/gin"
16
)
17

18
type CourseController struct {
19
        service            service.CourseServiceInterface
20
        aiClient           *ai.AiClient
21
        activityService    service.TeacherActivityServiceInterface
22
        notificationsQueue queues.NotificationsQueueInterface
23
}
24

25
func NewCourseController(service service.CourseServiceInterface, aiClient *ai.AiClient, activityService service.TeacherActivityServiceInterface, notificationsQueue queues.NotificationsQueueInterface) *CourseController {
1✔
26
        return &CourseController{
1✔
27
                service:            service,
1✔
28
                aiClient:           aiClient,
1✔
29
                activityService:    activityService,
1✔
30
                notificationsQueue: notificationsQueue,
1✔
31
        }
1✔
32
}
1✔
33

34
// @Summary Get all courses
35
// @Description Get all courses available in the database
36
// @Tags courses
37
// @Accept json
38
// @Produce json
39
// @Success 200 {array} model.Course
40
// @Router /courses [get]
41
func (c *CourseController) GetCourses(ctx *gin.Context) {
1✔
42
        slog.Debug("Getting courses")
1✔
43

1✔
44
        courses, err := c.service.GetCourses()
1✔
45
        if err != nil {
2✔
46
                slog.Error("Error getting courses", "error", err)
1✔
47
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
1✔
48
                return
1✔
49
        }
1✔
50
        slog.Debug("Courses retrieved", "courses", courses)
1✔
51
        ctx.JSON(http.StatusOK, courses)
1✔
52
}
53

54
// @Summary Course creation
55
// @Description Create a new course
56
// @Tags courses
57
// @Accept json
58
// @Produce json
59
// @Param course body schemas.CreateCourseRequest true "Course to create"
60
// @Success 201 {object} model.Course
61
// @Router /courses [post]
62
func (c *CourseController) CreateCourse(ctx *gin.Context) {
1✔
63
        slog.Debug("Creating course")
1✔
64

1✔
65
        var course schemas.CreateCourseRequest
1✔
66
        if err := ctx.ShouldBindJSON(&course); err != nil {
2✔
67
                slog.Error("Error binding JSON", "error", err)
1✔
68
                ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
1✔
69
                return
1✔
70
        }
1✔
71

72
        createdCourse, err := c.service.CreateCourse(course)
1✔
73
        if err != nil {
2✔
74
                slog.Error("Error creating course", "error", err)
1✔
75
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
1✔
76
                return
1✔
77
        }
1✔
78
        slog.Debug("Course created", "course", createdCourse)
1✔
79
        ctx.JSON(http.StatusCreated, createdCourse)
1✔
80
}
81

82
// @Summary Get a course by ID
83
// @Description Get a course by ID
84
// @Tags courses
85
// @Accept json
86
// @Produce json
87
// @Param id path string true "Course ID"
88
// @Success 200 {object} model.Course
89
// @Router /courses/{id} [get]
90
func (c *CourseController) GetCourseById(ctx *gin.Context) {
1✔
91
        slog.Debug("Getting course by ID")
1✔
92

1✔
93
        id := ctx.Param("id")
1✔
94
        course, err := c.service.GetCourseById(id)
1✔
95
        if err != nil {
2✔
96
                slog.Error("Error getting course by ID", "error", err)
1✔
97
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
1✔
98
                return
1✔
99
        }
1✔
100
        slog.Debug("Course retrieved", "course", course)
1✔
101
        ctx.JSON(http.StatusOK, course)
1✔
102
}
103

104
// @Summary Delete a course
105
// @Description Delete a course by ID
106
// @Tags courses
107
// @Accept json
108
// @Produce json
109
// @Param id path string true "Course ID"
110
// @Param teacherId query string true "Teacher ID"
111
// @Success 200 {object} schemas.DeleteCourseResponse
112
// @Router /courses/{id} [delete]
113
func (c *CourseController) DeleteCourse(ctx *gin.Context) {
1✔
114
        slog.Debug("Deleting course")
1✔
115
        id := ctx.Param("id")
1✔
116
        if id == "" {
1✔
NEW
117
                slog.Error("Course ID is required")
×
NEW
118
                ctx.JSON(http.StatusBadRequest, gin.H{"error": "Course ID is required"})
×
NEW
119
                return
×
NEW
120
        }
×
121

122
        teacherId := ctx.Query("teacherId")
1✔
123
        if teacherId == "" {
2✔
124
                slog.Error("Teacher ID is required")
1✔
125
                ctx.JSON(http.StatusBadRequest, gin.H{"error": "Teacher ID is required"})
1✔
126
                return
1✔
127
        }
1✔
128

129
        err := c.service.DeleteCourse(id, teacherId)
1✔
130
        if err != nil {
2✔
131
                slog.Error("Error deleting course", "error", err)
1✔
132
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
1✔
133
                return
1✔
134
        }
1✔
135
        slog.Debug("Course deleted", "id", id)
1✔
136
        ctx.JSON(http.StatusOK, gin.H{"message": "Course deleted successfully"})
1✔
137
}
138

139
// @Summary Get a course by teacher ID
140
// @Description Get a course by teacher ID
141
// @Tags courses
142
// @Accept json
143
// @Produce json
144
// @Param teacherId path string true "Teacher ID"
145
// @Success 200 {array} model.Course
146
// @Router /courses/teacher/{teacherId} [get]
147
func (c *CourseController) GetCourseByTeacherId(ctx *gin.Context) {
1✔
148
        slog.Debug("Getting course by teacher ID")
1✔
149
        teacherId := ctx.Param("teacherId")
1✔
150
        course, err := c.service.GetCourseByTeacherId(teacherId)
1✔
151
        if err != nil {
2✔
152
                slog.Error("Error getting course by teacher ID", "error", err)
1✔
153
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
1✔
154
                return
1✔
155
        }
1✔
156
        slog.Debug("Course retrieved", "course", course)
1✔
157
        ctx.JSON(http.StatusOK, course)
1✔
158
}
159

160
// @Summary Get a course by title
161
// @Description Get a course by title
162
// @Tags courses
163
// @Accept json
164
// @Produce json
165
// @Param title path string true "Course title"
166
// @Success 200 {array} model.Course
167
// @Router /courses/title/{title} [get]
168
func (c *CourseController) GetCourseByTitle(ctx *gin.Context) {
1✔
169
        slog.Debug("Getting course by title")
1✔
170
        title := ctx.Param("title")
1✔
171
        course, err := c.service.GetCourseByTitle(title)
1✔
172
        if err != nil {
1✔
UNCOV
173
                slog.Error("Error getting course by title", "error", err)
×
UNCOV
174
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
×
UNCOV
175
                return
×
UNCOV
176
        }
×
177
        if len(course) == 0 {
2✔
178
                slog.Error("Course not found")
1✔
179
                ctx.JSON(http.StatusNotFound, gin.H{"error": "Course not found"})
1✔
180
                return
1✔
181
        }
1✔
UNCOV
182
        slog.Debug("Course retrieved", "course", course)
×
UNCOV
183
        ctx.JSON(http.StatusOK, course)
×
184
}
185

186
// @Summary Update a course
187
// @Description Update a course by ID
188
// @Tags courses
189
// @Accept json
190
// @Produce json
191
// @Param id path string true "Course ID"
192
// @Param course body schemas.UpdateCourseRequest true "Course to update"
193
// @Success 200 {object} model.Course
194
// @Router /courses/{id} [put]
195
func (c *CourseController) UpdateCourse(ctx *gin.Context) {
1✔
196
        slog.Debug("Updating course")
1✔
197
        id := ctx.Param("id")
1✔
198

1✔
199
        var updateCourseRequest schemas.UpdateCourseRequest
1✔
200
        if err := ctx.ShouldBindJSON(&updateCourseRequest); err != nil {
2✔
201
                slog.Error("Error binding JSON", "error", err)
1✔
202
                ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
1✔
203
                return
1✔
204
        }
1✔
205

206
        updatedCourse, err := c.service.UpdateCourse(id, updateCourseRequest)
1✔
207
        if err != nil {
2✔
208
                slog.Error("Error updating course", "error", err)
1✔
209
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
1✔
210
                return
1✔
211
        }
1✔
212
        slog.Debug("Course updated", "course", updatedCourse)
1✔
213
        ctx.JSON(http.StatusOK, updatedCourse)
1✔
214
}
215

216
// @Summary Get courses by student ID
217
// @Description Get courses by student ID
218
// @Tags courses
219
// @Accept json
220
// @Produce json
221
// @Param studentId path string true "Student ID"
222
// @Success 200 {array} model.Course
223
// @Router /courses/student/{studentId} [get]
224
func (c *CourseController) GetCoursesByStudentId(ctx *gin.Context) {
1✔
225
        slog.Debug("Getting courses by student ID")
1✔
226
        studentId := ctx.Param("studentId")
1✔
227
        courses, err := c.service.GetCoursesByStudentId(studentId)
1✔
228
        if err != nil {
2✔
229
                slog.Error("Error getting courses by student ID", "error", err)
1✔
230
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
1✔
231
                return
1✔
232
        }
1✔
233
        slog.Debug("Courses retrieved", "courses", courses)
1✔
234
        ctx.JSON(http.StatusOK, courses)
1✔
235
}
236

237
// @Summary Get courses by user ID
238
// @Description Get courses by user ID
239
// @Tags courses
240
// @Accept json
241
// @Produce json
242
// @Param userId path string true "User ID"
243
// @Success 200 {array} model.Course
244
// @Router /courses/user/{userId} [get]
245
func (c *CourseController) GetCoursesByUserId(ctx *gin.Context) {
1✔
246
        slog.Debug("Getting courses by user ID")
1✔
247
        userId := ctx.Param("userId")
1✔
248
        courses, err := c.service.GetCoursesByUserId(userId)
1✔
249
        if err != nil {
2✔
250
                slog.Error("Error getting courses by user ID", "error", err)
1✔
251
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
1✔
252
                return
1✔
253
        }
1✔
254
        slog.Debug("Courses retrieved", "courses", courses)
1✔
255
        ctx.JSON(http.StatusOK, courses)
1✔
256
}
257

258
// @Summary Add an aux teacher to a course
259
// @Description Add an aux teacher to a course by ID
260
// @Tags courses
261
// @Accept json
262
// @Produce json
263
// @Param id path string true "Course ID"
264
func (c *CourseController) AddAuxTeacherToCourse(ctx *gin.Context) {
1✔
265
        slog.Debug("Adding aux teacher to course")
1✔
266
        id := ctx.Param("id")
1✔
267
        if id == "" {
2✔
268
                slog.Error("Course ID is required")
1✔
269
                ctx.JSON(http.StatusBadRequest, gin.H{"error": "Course ID is required"})
1✔
270
                return
1✔
271
        }
1✔
272

273
        var auxTeacherRequest schemas.AddAuxTeacherToCourseRequest
1✔
274
        if err := ctx.ShouldBindJSON(&auxTeacherRequest); err != nil {
2✔
275
                slog.Error("Error binding JSON", "error", err)
1✔
276
                ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
1✔
277
                return
1✔
278
        }
1✔
279

280
        teacherId := auxTeacherRequest.TeacherID
1✔
281
        auxTeacherId := auxTeacherRequest.AuxTeacherID
1✔
282
        course, err := c.service.AddAuxTeacherToCourse(id, teacherId, auxTeacherId)
1✔
283
        if err != nil {
2✔
284
                slog.Error("Error adding aux teacher to course", "error", err)
1✔
285
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
1✔
286
                return
1✔
287
        }
1✔
288
        slog.Debug("Aux teacher added to course", "course", course)
1✔
289

1✔
290
        message := queues.NewAddedAuxTeacherToCourseMessage(id, course.Title, auxTeacherId)
1✔
291
        slog.Info("Publishing message", "message", message)
1✔
292
        err = c.notificationsQueue.Publish(message)
1✔
293
        if err != nil {
1✔
NEW
294
                slog.Error("Error publishing message", "error", err)
×
NEW
295
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
×
NEW
296
                return
×
NEW
297
        }
×
298
        ctx.JSON(http.StatusOK, course)
1✔
299
}
300

301
// @Summary Remove an aux teacher from a course
302
// @Description Remove an aux teacher from a course by ID
303
// @Tags courses
304
// @Accept json
305
// @Produce json
306
// @Param id path string true "Course ID"
307
// @Param teacherId query string true "Teacher ID"
308
// @Param auxTeacherId query string true "Aux teacher ID"
309
// @Success 200 {object} model.Course
310
// @Router /courses/{id}/aux-teacher/remove [delete]
311
func (c *CourseController) RemoveAuxTeacherFromCourse(ctx *gin.Context) {
1✔
312
        slog.Debug("Removing aux teacher from course")
1✔
313
        id := ctx.Param("id")
1✔
314
        if id == "" {
2✔
315
                slog.Error("Course ID is required")
1✔
316
                ctx.JSON(http.StatusBadRequest, gin.H{"error": "Course ID is required"})
1✔
317
                return
1✔
318
        }
1✔
319

320
        teacherId := ctx.Query("teacherId")
1✔
321
        auxTeacherId := ctx.Query("auxTeacherId")
1✔
322

1✔
323
        if teacherId == "" || auxTeacherId == "" {
2✔
324
                slog.Error("Teacher ID and aux teacher ID are required")
1✔
325
                ctx.JSON(http.StatusBadRequest, gin.H{"error": "Teacher ID and aux teacher ID are required"})
1✔
326
                return
1✔
327
        }
1✔
328

329
        course, err := c.service.RemoveAuxTeacherFromCourse(id, teacherId, auxTeacherId)
1✔
330
        if err != nil {
2✔
331
                slog.Error("Error removing aux teacher from course", "error", err)
1✔
332
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
1✔
333
                return
1✔
334
        }
1✔
335
        slog.Debug("Aux teacher removed from course", "course", course)
1✔
336

1✔
337
        message := queues.NewRemoveAuxTeacherFromCourseMessage(id, course.Title, auxTeacherId)
1✔
338
        slog.Info("Publishing message", "message", message)
1✔
339
        err = c.notificationsQueue.Publish(message)
1✔
340
        if err != nil {
1✔
NEW
341
                slog.Error("Error publishing message", "error", err)
×
NEW
342
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
×
NEW
343
                return
×
NEW
344
        }
×
345
        ctx.JSON(http.StatusOK, course)
1✔
346
}
347

348
// @Summary Get favourite courses
349
// @Description Get favourite courses by student ID
350
// @Tags courses
351
// @Accept json
352
// @Produce json
353
// @Param studentId path string true "Student ID"
354
// @Success 200 {array} model.Course
355
// @Router /courses/favourite/{studentId} [get]
356
func (c *CourseController) GetFavouriteCourses(ctx *gin.Context) {
1✔
357
        slog.Debug("Getting favourite courses")
1✔
358
        studentId := ctx.Param("studentId")
1✔
359
        if studentId == "" {
2✔
360
                slog.Error("Student ID is required")
1✔
361
                ctx.JSON(http.StatusBadRequest, gin.H{"error": "Student ID is required"})
1✔
362
                return
1✔
363
        }
1✔
364

365
        courses, err := c.service.GetFavouriteCourses(studentId)
1✔
366
        if err != nil {
2✔
367
                slog.Error("Error getting favourite courses", "error", err)
1✔
368
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
1✔
369
                return
1✔
370
        }
1✔
371
        slog.Debug("Favourite courses retrieved", "courses", courses)
1✔
372
        ctx.JSON(http.StatusOK, courses)
1✔
373
}
374

375
// @Summary Create course feedback
376
// @Description Create course feedback by course ID
377
// @Tags courses
378
// @Accept json
379
// @Produce json
380
// @Param id path string true "Course ID"
381
// @Param feedback body schemas.CreateCourseFeedbackRequest true "Course feedback"
382
// @Success 200 {object} model.CourseFeedback
383
// @Router /courses/{id}/feedback [post]
384
func (c *CourseController) CreateCourseFeedback(ctx *gin.Context) {
1✔
385
        slog.Debug("Creating course feedback")
1✔
386
        courseId := ctx.Param("id")
1✔
387
        if courseId == "" {
2✔
388
                slog.Error("Course ID is required")
1✔
389
                ctx.JSON(http.StatusBadRequest, gin.H{"error": "Course ID is required"})
1✔
390
                return
1✔
391
        }
1✔
392

393
        var feedback schemas.CreateCourseFeedbackRequest
1✔
394
        if err := ctx.ShouldBindJSON(&feedback); err != nil {
2✔
395
                slog.Error("Error binding create course feedback request", "error", err)
1✔
396
                ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
1✔
397
                return
1✔
398
        }
1✔
399

400
        if !slices.Contains(model.FeedbackTypes, feedback.FeedbackType) {
2✔
401
                slog.Error("Invalid feedback type")
1✔
402
                ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid feedback type"})
1✔
403
                return
1✔
404
        }
1✔
405

406
        feedbackModel, err := c.service.CreateCourseFeedback(courseId, feedback)
1✔
407
        if err != nil {
2✔
408
                slog.Error("Error creating course feedback", "error", err)
1✔
409
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
1✔
410
                return
1✔
411
        }
1✔
412

413
        // Log activity if teacher is auxiliary
414
        teacherUUID := ctx.GetHeader("X-Teacher-UUID")
1✔
415
        if teacherUUID != "" {
1✔
NEW
416
                c.activityService.LogActivityIfAuxTeacher(
×
NEW
417
                        courseId,
×
NEW
418
                        teacherUUID,
×
NEW
419
                        "CREATE_COURSE_FEEDBACK",
×
NEW
420
                        fmt.Sprintf("Created course feedback of type: %s", feedback.FeedbackType),
×
NEW
421
                )
×
NEW
422
        }
×
423

424
        slog.Debug("Course feedback created", "feedback", feedbackModel)
1✔
425

1✔
426
        // Getting the course so we have the teacher ID
1✔
427
        course, err := c.service.GetCourseById(courseId)
1✔
428
        if err != nil {
1✔
NEW
429
                slog.Error("Error getting course", "error", err)
×
NEW
430
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
×
NEW
431
                return
×
NEW
432
        }
×
433

434
        message := queues.NewFeedbackCreatedMessage(course.TeacherUUID, courseId, feedbackModel.ID.Hex(), feedbackModel.Feedback, feedbackModel.Score, feedbackModel.CreatedAt)
1✔
435
        slog.Info("Publishing message", "message", message)
1✔
436
        err = c.notificationsQueue.Publish(message)
1✔
437
        if err != nil {
1✔
NEW
438
                slog.Error("Error publishing message", "error", err)
×
NEW
439
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
×
NEW
440
                return
×
NEW
441
        }
×
442
        ctx.JSON(http.StatusOK, feedbackModel)
1✔
443
}
444

445
// @Summary Get course feedback
446
// @Description Get course feedback by course ID
447
// @Tags courses
448
// @Accept json
449
// @Produce json
450
// @Param id path string true "Course ID"
451
// @Param getCourseFeedbackRequest body schemas.GetCourseFeedbackRequest true "Get course feedback request"
452
// @Success 200 {array} model.CourseFeedback
453
// @Router /courses/{id}/feedback [put]
454
func (c *CourseController) GetCourseFeedback(ctx *gin.Context) {
1✔
455
        slog.Debug("Getting course feedback")
1✔
456
        courseId := ctx.Param("id")
1✔
457
        if courseId == "" {
2✔
458
                slog.Error("Course ID is required")
1✔
459
                ctx.JSON(http.StatusBadRequest, gin.H{"error": "Course ID is required"})
1✔
460
                return
1✔
461
        }
1✔
462

463
        var getCourseFeedbackRequest schemas.GetCourseFeedbackRequest
1✔
464
        if err := ctx.ShouldBindJSON(&getCourseFeedbackRequest); err != nil {
2✔
465
                slog.Error("Error binding get course feedback request", "error", err)
1✔
466
                ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
1✔
467
                return
1✔
468
        }
1✔
469

470
        feedback, err := c.service.GetCourseFeedback(courseId, getCourseFeedbackRequest)
1✔
471
        if err != nil {
2✔
472
                slog.Error("Error getting course feedback", "error", err)
1✔
473
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
1✔
474
                return
1✔
475
        }
1✔
476

477
        slog.Debug("Course feedback retrieved", "feedback", feedback)
1✔
478
        ctx.JSON(http.StatusOK, feedback)
1✔
479
}
480

481
// @Summary Get course feedback summary
482
// @Description Get course feedback summary by course ID
483
// @Tags courses
484
// @Accept json
485
// @Produce json
486
// @Param id path string true "Course ID"
487
// @Success 200 {object} schemas.AiSummaryResponse
488
// @Router /courses/{id}/feedback/summary [get]
489
func (c *CourseController) GetCourseFeedbackSummary(ctx *gin.Context) {
×
490
        slog.Debug("Getting course feedback summary")
×
491
        courseId := ctx.Param("id")
×
492
        if courseId == "" {
×
493
                slog.Error("Course ID is required")
×
494
                ctx.JSON(http.StatusBadRequest, gin.H{"error": "Course ID is required"})
×
495
                return
×
496
        }
×
497

498
        feedbacks, err := c.service.GetCourseFeedback(courseId, schemas.GetCourseFeedbackRequest{})
×
499
        if err != nil {
×
500
                slog.Error("Error getting course feedback", "error", err)
×
501
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
×
502
                return
×
503
        }
×
504

505
        if len(feedbacks) == 0 {
×
506
                slog.Error("No feedbacks found")
×
507
                ctx.JSON(http.StatusNotFound, gin.H{"error": "No feedbacks found"})
×
508
                return
×
509
        }
×
510

511
        summary, err := c.aiClient.SummarizeCourseFeedbacks(feedbacks)
×
512
        if err != nil {
×
513
                slog.Error("Error getting course feedback summary", "error", err)
×
514
                ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
×
515
                return
×
516
        }
×
517

518
        slog.Debug("Course feedback summary retrieved", "summary", summary)
×
NEW
519
        ctx.JSON(http.StatusOK, schemas.AiSummaryResponse{Summary: summary})
×
520
}
521

522
// @Summary Get course members
523
// @Description Get all members of a course (teacher, aux teachers, and students)
524
// @Tags courses
525
// @Accept json
526
// @Produce json
527
// @Param id path string true "Course ID"
528
// @Success 200 {object} schemas.CourseMembersResponse
529
// @Failure 400 {object} schemas.ErrorResponse
530
// @Failure 404 {object} schemas.ErrorResponse
531
// @Failure 500 {object} schemas.ErrorResponse
532
// @Router /courses/{id}/members [get]
533
func (c *CourseController) GetCourseMembers(ctx *gin.Context) {
1✔
534
        slog.Debug("Getting course members")
1✔
535

1✔
536
        courseId := ctx.Param("id")
1✔
537
        if courseId == "" {
1✔
538
                ctx.JSON(http.StatusBadRequest, schemas.ErrorResponse{Error: "Course ID is required"})
×
539
                return
×
540
        }
×
541

542
        members, err := c.service.GetCourseMembers(courseId)
1✔
543
        if err != nil {
2✔
544
                slog.Error("Error getting course members", "error", err)
1✔
545
                ctx.JSON(http.StatusInternalServerError, schemas.ErrorResponse{Error: err.Error()})
1✔
546
                return
1✔
547
        }
1✔
548

549
        slog.Debug("Course members retrieved", "course_id", courseId)
1✔
550
        ctx.JSON(http.StatusOK, members)
1✔
551
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc