From ca80508a1e94e6f89af86242c11c1b5778e4f05c Mon Sep 17 00:00:00 2001 From: johanneskarrer Date: Mon, 30 Sep 2024 13:30:18 +0200 Subject: [PATCH] commented exported functions/methods; ensured urlParams (firstSemester and lastSemester) validity once more --- api/search.go | 32 +++++++++++++++++++++++++------- model/semester.go | 2 ++ model/user.go | 4 ++++ tools/meiliExporter.go | 3 +++ tools/meiliSearch.go | 3 +++ 5 files changed, 37 insertions(+), 7 deletions(-) diff --git a/api/search.go b/api/search.go index 758f7d899..59fe7168a 100644 --- a/api/search.go +++ b/api/search.go @@ -88,7 +88,7 @@ func getDefaultParameters(c *gin.Context) (*model.User, string, uint64) { user := c.MustGet("TUMLiveContext").(tools.TUMLiveContext).User query := c.Query("q") limit, err := strconv.ParseUint(c.Query("limit"), 10, 16) - if err != nil || limit > math.MaxInt64 { // second condition should never happen, max bitSize for parseuint is 16 + if err != nil || limit > math.MaxInt64 { // second condition should never evaluate to true (maximum bitSize for ParseUint is 16) limit = DefaultLimit } return user, query, limit @@ -157,7 +157,7 @@ func semesterSearchHelper(c *gin.Context, m tools.MeiliSearchInterface, query st semesters1, err1 := parseSemesters(firstSemesterParam) semesters2, err2 := parseSemesters(lastSemesterParam) semesters, err3 := parseSemesters(semestersParam) - if (err1 != nil || err2 != nil || len(semesters1) > 1 || len(semesters2) > 1) && err3 != nil { + if (err1 != nil || err2 != nil || len(semesters1) != 1 || len(semesters2) != 1) && err3 != nil { return nil, errors.New("wrong parameters") } rangeSearch := false @@ -344,8 +344,11 @@ func checkAndFillResponse(c *gin.Context, user *model.User, limit int64, daoWrap } } -// meilisearch filter +// meilisearch filters +// meiliSubtitleFilter returns a filter conforming to MeiliSearch filter format that can be used for filtering subtitles +// +// Checking eligibility to search in each course in courses is the caller's responsibility func meiliSubtitleFilter(user *model.User, courses []model.Course) string { if len(courses) == 0 { return "" @@ -363,6 +366,9 @@ func meiliSubtitleFilter(user *model.User, courses []model.Course) string { return fmt.Sprintf("streamID IN %s", uintSliceToString(streamIDs)) } +// meiliStreamFilter returns a filter conforming to MeiliSearch filter format that can be used for filtering streams +// +// Checking eligibility to search for courses and validation of model.Semester format is the caller's responsibility func meiliStreamFilter(c *gin.Context, user *model.User, semester model.Semester, courses []model.Course) string { if courses != nil { return fmt.Sprintf("courseID IN %s", courseSliceToString(courses)) @@ -394,6 +400,9 @@ func meiliStreamFilter(c *gin.Context, user *model.User, semester model.Semester return fmt.Sprintf("(%s AND %s)", permissionFilter, semesterFilter) } +// meiliCourseFilter returns a filter conforming to MeiliSearch filter format that can be used for filtering courses +// +// Validation of model.Semester format is the caller's responsibility func meiliCourseFilter(c *gin.Context, user *model.User, firstSemester model.Semester, lastSemester model.Semester, semesters []model.Semester) string { semesterFilter := meiliSemesterFilter(firstSemester, lastSemester, semesters) if user != nil && user.Role == model.AdminType { @@ -421,6 +430,9 @@ func meiliCourseFilter(c *gin.Context, user *model.User, firstSemester model.Sem return fmt.Sprintf("(%s AND %s)", permissionFilter, semesterFilter) } +// meiliSemesterFilter returns a filter conforming to MeiliSearch filter format +// +// Validation of model.Semester format is the caller's responsibility func meiliSemesterFilter(firstSemester model.Semester, lastSemester model.Semester, semesters []model.Semester) string { if len(semesters) == 0 && firstSemester.Year < 1900 && lastSemester.Year > 2800 { return "" @@ -448,7 +460,6 @@ func meiliSemesterFilter(firstSemester model.Semester, lastSemester model.Semest return fmt.Sprintf("(%s OR (year > %d AND year < %d) OR %s)", constraint1, firstSemester.Year, lastSemester.Year, constraint2) } return fmt.Sprintf("(%s OR %s)", constraint1, constraint2) - } semesterStringsSlice := make([]string, len(semesters)) @@ -487,7 +498,9 @@ func parseSemesters(semestersParam string) ([]model.Semester, error) { return semesters, nil } -// parses the URL Parameter course (urlParamCourse) and returns a slice containing every course in the parameter or an error code +// parseCourses parses the URL Parameter course (urlParamCourse) and returns a slice containing every course in the parameter or an error code +// +// Checking if the user is allowed to see returned courses is the caller's responsibility func parseCourses(c *gin.Context, daoWrapper dao.DaoWrapper, urlParamCourse string) ([]model.Course, uint) { coursesStrings := strings.Split(urlParamCourse, ",") @@ -536,6 +549,7 @@ func uintSliceToString(ids []uint) string { return filter } +// ToSearchCourseDTO converts Courses to slice of SearchCourseDTO func ToSearchCourseDTO(cs ...model.Course) []SearchCourseDTO { res := make([]SearchCourseDTO, len(cs)) for i, c := range cs { @@ -549,7 +563,9 @@ func ToSearchCourseDTO(cs ...model.Course) []SearchCourseDTO { return res } -// ToSearchStreamDTO ignores any errors and sets affected fields to zero value +// ToSearchStreamDTO converts Streams to slice of SearchStreamDTO +// +// Ignores any errors and sets affected fields to zero value func ToSearchStreamDTO(wrapper dao.DaoWrapper, streams ...model.Stream) []SearchStreamDTO { res := make([]SearchStreamDTO, len(streams)) for i, s := range streams { @@ -575,7 +591,9 @@ func ToSearchStreamDTO(wrapper dao.DaoWrapper, streams ...model.Stream) []Search return res } -// ToSearchSubtitleDTO ignores any errors and sets affected fields to zero value +// ToSearchSubtitleDTO converts MeiliSubtitles to slice of SearchSubtitlesDTO +// +// Ignores any errors and sets affected fields to zero value func ToSearchSubtitleDTO(wrapper dao.DaoWrapper, subtitles ...tools.MeiliSubtitles) []SearchSubtitlesDTO { res := make([]SearchSubtitlesDTO, len(subtitles)) for i, subtitle := range subtitles { diff --git a/model/semester.go b/model/semester.go index c6a27427f..928fc4d7c 100644 --- a/model/semester.go +++ b/model/semester.go @@ -5,6 +5,7 @@ type Semester struct { Year int } +// InRangeOfSemesters checks if s is between firstSemester (inclusive) and lastSemester (inclusive) or is element of semesters slice func (s *Semester) InRangeOfSemesters(firstSemester Semester, lastSemester Semester, semesters []Semester) bool { if s == nil { return false @@ -23,6 +24,7 @@ func (s *Semester) InRangeOfSemesters(firstSemester Semester, lastSemester Semes return false } +// GreaterEqualThan checks if s comes after or is equal to s1 func (s *Semester) GreaterEqualThan(s1 Semester) bool { if s == nil { return false diff --git a/model/user.go b/model/user.go index 486c7f7c2..a2333c2af 100755 --- a/model/user.go +++ b/model/user.go @@ -262,6 +262,7 @@ func (u *User) IsAdminOfCourse(course Course) bool { return u.Role == AdminType || course.UserID == u.ID } +// IsEligibleToWatchCourse checks if the user is allowed to access the course func (u *User) IsEligibleToWatchCourse(course Course) bool { if u == nil { return course.Visibility == "public" || course.Visibility == "hidden" @@ -277,6 +278,7 @@ func (u *User) IsEligibleToWatchCourse(course Course) bool { return u.IsAdminOfCourse(course) } +// IsEligibleToSearchForCourse is a stricter version of IsEligibleToWatchCourse; in case of hidden course, it returns true only when the user is an admin of the course func (u *User) IsEligibleToSearchForCourse(course Course) bool { return u.IsEligibleToWatchCourse(course) && course.Visibility != "hidden" || u.IsAdminOfCourse(course) } @@ -300,6 +302,7 @@ func (u *User) CoursesForSemester(year int, term string, context context.Context return cRes } +// AdministeredCoursesForSemesters returns all courses, that the user is a course admin of, in the given semester range or semesters func (u *User) AdministeredCoursesForSemesters(firstSemester Semester, lastSemester Semester, semesters []Semester) []Course { if u == nil { return make([]Course, 0) @@ -315,6 +318,7 @@ func (u *User) AdministeredCoursesForSemesters(firstSemester Semester, lastSemes return administeredCourses } +// CoursesForSemestersWithoutAdministeredCourses returns all courses of the user in the given semester range or semesters excluding administered courses func (u *User) CoursesForSemestersWithoutAdministeredCourses(firstSemester Semester, lastSemester Semester, semesters []Semester) []Course { if u == nil { return make([]Course, 0) diff --git a/tools/meiliExporter.go b/tools/meiliExporter.go index e96b4ce01..76a9ad1f9 100644 --- a/tools/meiliExporter.go +++ b/tools/meiliExporter.go @@ -60,6 +60,7 @@ func NewMeiliExporter(d dao.DaoWrapper) *MeiliExporter { return &MeiliExporter{c, d} } +// Export exports all relevant search data to MeiliSearch Instance func (m *MeiliExporter) Export() { if m == nil { return @@ -190,6 +191,7 @@ func (m *MeiliExporter) SetIndexSettings() { } } +// ToMeiliCourses converts slice of model.Course to slice of MeiliCourse func ToMeiliCourses(cs []model.Course) []MeiliCourse { res := make([]MeiliCourse, len(cs)) for i, c := range cs { @@ -205,6 +207,7 @@ func ToMeiliCourses(cs []model.Course) []MeiliCourse { return res } +// ToMeiliStreams converts slice of model.Stream to slice of MeiliStream func ToMeiliStreams(streams []model.Stream, daoWrapper dao.DaoWrapper) ([]MeiliStream, error) { res := make([]MeiliStream, len(streams)) for i, s := range streams { diff --git a/tools/meiliSearch.go b/tools/meiliSearch.go index ee4684d5e..b30636f65 100644 --- a/tools/meiliSearch.go +++ b/tools/meiliSearch.go @@ -68,6 +68,9 @@ func getCoursesSearchRequest(q string, limit int64, courseFilter string) meilise return req } +// Search passes search requests on to MeiliSearch instance and returns the results +// +// searchType specifies bit-wise which indexes should be searched (lowest bit set to 1: Index SUBTITLES | second-lowest bit set to 1: Index STREAMS | third-lowest bit set to 1: Index COURSES) func (d *meiliSearchFunctions) Search(q string, limit int64, searchType int, courseFilter string, streamFilter string, subtitleFilter string) *meilisearch.MultiSearchResponse { c, err := Cfg.GetMeiliClient() if err != nil {