Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions internal/handlers/courses/courses.go
Original file line number Diff line number Diff line change
Expand Up @@ -473,13 +473,13 @@
return
}

filter_criteria, err := utils.GetFilterCriteria(context)
filterCriteria, err := utils.GetFilterCriteria(context)
if err != nil {
_ = context.Error(err)
return
}

courses, err := c.service.GetCourses(filter_criteria, page)
courses, err := c.service.GetCourses(filterCriteria, page)
if err != nil {
_ = context.Error(err)
return
Expand Down Expand Up @@ -523,7 +523,13 @@
return
}

courses, err := c.service.GetCoursesByUser(parseUserID, page)
filterCriteria, err := utils.GetFilterCriteria(context)
if err != nil {
_ = context.Error(err)
return
}

Check warning on line 530 in internal/handlers/courses/courses.go

View check run for this annotation

Codecov / codecov/patch

internal/handlers/courses/courses.go#L528-L530

Added lines #L528 - L530 were not covered by tests

courses, err := c.service.GetCoursesByUser(parseUserID, page, filterCriteria)
if err != nil {
_ = context.Error(err)
return
Expand Down
49 changes: 32 additions & 17 deletions internal/repository/courses.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,16 +236,16 @@
return auxProfessors, nil
}

func (db *CoursesRepositoryImpl) GetCourses(filter_criteria models.FilterIF, page int) ([]models.Course, error) {
func (db *CoursesRepositoryImpl) GetCourses(filterCriteria models.FilterIF, page int) ([]models.Course, error) {
builder := sq.Select(`
id, owner_id, title, description, syllabus, picture, capacity, credits_needed,
min_education, credits_awarded, passing_grade, status, inscription_ends, created_at, updated_at`).
From("courses").
Limit(uint64(config.CoursesPerPage)).
Offset(uint64(config.CoursesPerPage * (page - 1)))

if filter_criteria != nil {
builder = filter_criteria.Apply(builder)
if filterCriteria != nil {
builder = filterCriteria.Apply(builder)
}

query, args, err := builder.PlaceholderFormat(sq.Dollar).ToSql()
Expand Down Expand Up @@ -287,21 +287,36 @@
return courses, nil
}

func (db *CoursesRepositoryImpl) GetCoursesByUser(id uuid.UUID, page int) ([]models.Course, error) {
query := `
SELECT DISTINCT
c.id, c.owner_id, c.title, c.description, c.syllabus, c.picture,
c.capacity, c.credits_needed, c.min_education, c.credits_awarded, c.passing_grade, c.status,
c.inscription_ends, c.created_at, c.updated_at
FROM courses c
LEFT JOIN enrollments e ON e.course_id = c.id
LEFT JOIN aux_professors ap ON ap.course_id = c.id
WHERE c.owner_id = $1 OR e.student_id = $1 OR ap.user_id = $1
ORDER BY c.created_at DESC
LIMIT $2 OFFSET $3;
`
func (db *CoursesRepositoryImpl) GetCoursesByUser(id uuid.UUID, page int, filterCriteria models.FilterIF) ([]models.Course, error) {
builder := sq.
Select(
"c.id", "c.owner_id", "c.title", "c.description", "c.syllabus", "c.picture",
"c.capacity", "c.credits_needed", "c.min_education", "c.credits_awarded",
"c.passing_grade", "c.status", "c.inscription_ends", "c.created_at", "c.updated_at",
).
Distinct().
From("courses c").
LeftJoin("enrollments e ON e.course_id = c.id").
LeftJoin("aux_professors ap ON ap.course_id = c.id").
Where(sq.Or{
sq.Eq{"c.owner_id": id},
sq.Eq{"e.student_id": id},
sq.Eq{"ap.user_id": id},
}).
OrderBy("c.created_at DESC").
Limit(uint64(config.CoursesPerPage)).
Offset(uint64(config.CoursesPerPage * (page - 1)))

if filterCriteria != nil {
builder = filterCriteria.Apply(builder)
}

Check warning on line 312 in internal/repository/courses.go

View check run for this annotation

Codecov / codecov/patch

internal/repository/courses.go#L311-L312

Added lines #L311 - L312 were not covered by tests

rows, err := db.conn.Query(context.Background(), query, id, config.CoursesPerPage, config.CoursesPerPage*(page-1))
query, args, err := builder.PlaceholderFormat(sq.Dollar).ToSql()
if err != nil {
return nil, errors.NewInternalServerError("Error building SQL query: " + err.Error())
}

Check warning on line 317 in internal/repository/courses.go

View check run for this annotation

Codecov / codecov/patch

internal/repository/courses.go#L316-L317

Added lines #L316 - L317 were not covered by tests

rows, err := db.conn.Query(context.Background(), query, args...)
if err != nil {
return nil, errors.NewInternalServerError("Internal server Error: " + err.Error())
}
Expand Down
24 changes: 7 additions & 17 deletions internal/repository/courses_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,20 +163,15 @@ func TestGetCoursesByUser_NotFound(t *testing.T) {
mock, repo := setupMockRepoForCourses(t)
userID := uuid.New()

mock.ExpectQuery(`SELECT DISTINCT c.id, c.owner_id, c.title, c.description, c.syllabus, c.picture, c.capacity, c.credits_needed, c.min_education, c.credits_awarded, c.passing_grade, c.status, c.inscription_ends, c.created_at, c.updated_at
FROM courses c
LEFT JOIN enrollments e ON e.course_id = c.id
LEFT JOIN aux_professors ap ON ap.course_id = c.id
WHERE c.owner_id = \$1 OR e.student_id = \$1 OR ap.user_id = \$1
ORDER BY c.created_at DESC LIMIT \$2 OFFSET \$3;`).
WithArgs(userID, 10, 0).
mock.ExpectQuery(`(?s)^SELECT DISTINCT c\.id, c\.owner_id, c\.title, c\.description, c\.syllabus, c\.picture, c\.capacity, c\.credits_needed, c\.min_education, c\.credits_awarded, c\.passing_grade, c\.status, c\.inscription_ends, c\.created_at, c\.updated_at FROM courses c LEFT JOIN enrollments e ON e\.course_id = c\.id LEFT JOIN aux_professors ap ON ap\.course_id = c\.id WHERE \(c\.owner_id = \$1 OR e\.student_id = \$2 OR ap\.user_id = \$3\) ORDER BY c\.created_at DESC LIMIT 10 OFFSET 0$`).
WithArgs(userID.String(), userID.String(), userID.String()).
WillReturnRows(pgxmock.NewRows([]string{
"id", "owner_id", "title", "description", "syllabus", "picture",
"capacity", "credits_needed", "min_education", "credits_awarded", "passing_grade", "status",
"inscription_ends", "created_at", "updated_at",
}))

courses, err := repo.GetCoursesByUser(userID, 1)
courses, err := repo.GetCoursesByUser(userID, 1, nil)
assert.Nil(t, err)
assert.Empty(t, courses)
}
Expand All @@ -187,23 +182,18 @@ func TestGetCoursesByUser_Success(t *testing.T) {
courseID := uuid.New()
now := time.Now()

mock.ExpectQuery(`SELECT DISTINCT c.id, c.owner_id, c.title, c.description, c.syllabus, c.picture, c.capacity, c.credits_needed, c.min_education, c.credits_awarded, c.passing_grade, c.status, c.inscription_ends, c.created_at, c.updated_at
FROM courses c
LEFT JOIN enrollments e ON e.course_id = c.id
LEFT JOIN aux_professors ap ON ap.course_id = c.id
WHERE c.owner_id = \$1 OR e.student_id = \$1 OR ap.user_id = \$1
ORDER BY c.created_at DESC LIMIT \$2 OFFSET \$3;`).
WithArgs(userID, 10, 0).
mock.ExpectQuery(`(?s)^SELECT DISTINCT c\.id, c\.owner_id, c\.title, c\.description, c\.syllabus, c\.picture, c\.capacity, c\.credits_needed, c\.min_education, c\.credits_awarded, c\.passing_grade, c\.status, c\.inscription_ends, c\.created_at, c\.updated_at FROM courses c LEFT JOIN enrollments e ON e\.course_id = c\.id LEFT JOIN aux_professors ap ON ap\.course_id = c\.id WHERE \(c\.owner_id = \$1 OR e\.student_id = \$2 OR ap\.user_id = \$3\) ORDER BY c\.created_at DESC LIMIT 10 OFFSET 0$`).
WithArgs(userID.String(), userID.String(), userID.String()).
WillReturnRows(pgxmock.NewRows([]string{
"id", "owner_id", "title", "description", "syllabus", "picture",
"capacity", "credits_needed", "min_education", "credits_awarded", "passing_grade", "status",
"inscription_ends", "created_at", "updated_at",
}).AddRow(
courseID, userID, "Go 101", "Intro to Go", "Week 1", "pic.jpg", 30, 3,
models.HighSchool, 2, 4.0, models.CourseActive, time.Now().AddDate(0, 1, 0), now, now,
models.HighSchool, 2, 4.0, models.CourseActive, now.AddDate(0, 1, 0), now, now,
))

courses, err := repo.GetCoursesByUser(userID, 1)
courses, err := repo.GetCoursesByUser(userID, 1, nil)
assert.NoError(t, err)
assert.Len(t, courses, 1)
assert.Equal(t, courseID, courses[0].Id)
Expand Down
2 changes: 1 addition & 1 deletion internal/repository/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type CoursesRepository interface {

IsCourseProfessor(courseID, userID uuid.UUID) (bool, error)
GetCourses(string models.FilterIF, page int) ([]models.Course, error)
GetCoursesByUser(id uuid.UUID, page int) ([]models.Course, error)
GetCoursesByUser(id uuid.UUID, page int, filterCriteria models.FilterIF) ([]models.Course, error)
GetCourseByID(id uuid.UUID) (*models.Course, error)
GetAuxProfessorsByCourse(courseID uuid.UUID) ([]uuid.UUID, error)

Expand Down
6 changes: 3 additions & 3 deletions internal/repository/memory/repository_memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (r *InMemoryCoursesRepository) GetCourses(_filter models.FilterIF, page int
return courses, nil
}

func (r *InMemoryCoursesRepository) GetCoursesByUser(studentID uuid.UUID, page int) ([]models.Course, error) {
func (r *InMemoryCoursesRepository) GetCoursesByUser(studentID uuid.UUID, page int, _filter models.FilterIF) ([]models.Course, error) {
if studentID == uuid.Nil {
return nil, errors.NewNotFoundError("Student ID cannot be nil")
}
Expand Down Expand Up @@ -358,7 +358,7 @@ func (r *InMemoryCoursesRepository) GetAssignmentsByCourse(courseID uuid.UUID, p
}

func (r *InMemoryCoursesRepository) GetAssignmentsByStudent(studentID uuid.UUID, page int) ([]models.Assignment, error) {
courses, err := r.GetCoursesByUser(studentID, page)
courses, err := r.GetCoursesByUser(studentID, page, nil)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -401,7 +401,7 @@ func (c *InMemoryCoursesRepository) GetExamsByStudent(userID uuid.UUID, page int
if userID == uuid.Nil {
return nil, errors.NewNotFoundError("User ID cannot be nil")
}
courses, err := c.GetCoursesByUser(userID, page)
courses, err := c.GetCoursesByUser(userID, page, nil)
if err != nil {
return nil, err
}
Expand Down
8 changes: 4 additions & 4 deletions internal/services/courses/course.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,16 +232,16 @@ func (c *coursesService) DeleteCoursePicture(courseID, userID uuid.UUID) (*model
return course, nil
}

func (c *coursesService) GetCourses(filter_criteria models.FilterIF, page int) ([]models.Course, error) {
courses, err := c.repo.GetCourses(filter_criteria, page)
func (c *coursesService) GetCourses(filterCriteria models.FilterIF, page int) ([]models.Course, error) {
courses, err := c.repo.GetCourses(filterCriteria, page)
if err != nil {
return []models.Course{}, err
}
return courses, nil
}

func (c *coursesService) GetCoursesByUser(studentID uuid.UUID, page int) ([]models.Course, error) {
courses, err := c.repo.GetCoursesByUser(studentID, page)
func (c *coursesService) GetCoursesByUser(studentID uuid.UUID, page int, filterCriteria models.FilterIF) ([]models.Course, error) {
courses, err := c.repo.GetCoursesByUser(studentID, page, filterCriteria)
if err != nil {
return []models.Course{}, err
}
Expand Down
4 changes: 2 additions & 2 deletions internal/services/courses/course_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,12 +242,12 @@ func TestGetCourses(t *testing.T) {
assert.NotEmpty(t, courses)

// By user
courses, err = service.GetCoursesByUser(uuid.Nil, 1)
courses, err = service.GetCoursesByUser(uuid.Nil, 1, nil)
assert.Error(t, err)
assert.IsType(t, err, &errors.NotFoundError{})
assert.Empty(t, courses)

courses, err = service.GetCoursesByUser(professorsIDs[1], 1)
courses, err = service.GetCoursesByUser(professorsIDs[1], 1, nil)
assert.NoError(t, err)
assert.NotEmpty(t, courses)
assert.Equal(t, 1, len(courses))
Expand Down
4 changes: 2 additions & 2 deletions internal/services/courses/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ type CoursesService interface {
AddRemoveAuxProfessor(courseID, auxProfessorID, userID uuid.UUID, add bool) error
GetAuxProfessorLogs(courseID, userID uuid.UUID, page int) ([]models.AuxProfessorLogEntry, error)

GetCourses(filter_criteria models.FilterIF, page int) ([]models.Course, error)
GetCoursesByUser(userID uuid.UUID, page int) ([]models.Course, error)
GetCourses(filterCriteria models.FilterIF, page int) ([]models.Course, error)
GetCoursesByUser(userID uuid.UUID, page int, filterCriteria models.FilterIF) ([]models.Course, error)
GetCourseByID(courseID uuid.UUID) (*models.Course, error)

GetAuxProfessorsByCourse(courseID uuid.UUID) ([]uuid.UUID, error)
Expand Down
6 changes: 3 additions & 3 deletions internal/utils/filtering.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,23 +59,23 @@ func GetFilterCriteria(c *gin.Context) (models.FilterIF, error) {
}
if modality, exists := queries["modality"]; exists && len(modality) > 0 {
modalityInt, _ := strconv.Atoi(modality[0])
if modalityInt < 0 || modalityInt >= int(models.Hybrid) {
if modalityInt < 0 || modalityInt > int(models.Hybrid) {
return nil, errors.NewBadRequestError("Invalid modality value")
}
modalityValue := models.Modality(modalityInt)
filters = append(filters, models.ByModality{Modality: modalityValue})
}
if minEducation, exists := queries["min_education"]; exists && len(minEducation) > 0 {
minEducationInt, _ := strconv.Atoi(minEducation[0])
if minEducationInt < 0 || minEducationInt >= int(models.DoctorateDegree) {
if minEducationInt < 0 || minEducationInt > int(models.DoctorateDegree) {
return nil, errors.NewBadRequestError("Invalid min_education value")
}
minEducationValue := models.Education(minEducationInt)
filters = append(filters, models.ByMinEducation{MinEducation: minEducationValue})
}
if status, exists := queries["status"]; exists && len(status) > 0 {
statusInt, _ := strconv.Atoi(status[0])
if statusInt < 0 || statusInt >= int(models.CourseCompleted) {
if statusInt < 0 || statusInt > int(models.CourseCompleted) {
return nil, errors.NewBadRequestError("Invalid status value")
}
statusValue := models.CourseStatus(statusInt)
Expand Down