@@ -83,6 +83,7 @@ func ProfessorSearch(c *gin.Context) {
8383 }
8484
8585 // return result
86+ print (len (professors ))
8687 c .JSON (http .StatusOK , responses.MultiProfessorResponse {Status : http .StatusOK , Message : "success" , Data : professors })
8788}
8889
@@ -143,3 +144,145 @@ func ProfessorAll(c *gin.Context) {
143144 // return result
144145 c .JSON (http .StatusOK , responses.MultiProfessorResponse {Status : http .StatusOK , Message : "success" , Data : professors })
145146}
147+
148+ // @Id professorCourseSearch
149+ // @Router /professor/courses [get]
150+ // @Description "Returns all of the courses of all the professors matching the query's string-typed key-value pairs"
151+ // @Produce json
152+ // @Param first_name query string false "The professor's first name"
153+ // @Param last_name query string false "The professor's last name"
154+ // @Param titles query string false "One of the professor's title"
155+ // @Param email query string false "The professor's email address"
156+ // @Param phone_number query string false "The professor's phone number"
157+ // @Param office.building query string false "The building of the location of the professor's office"
158+ // @Param office.room query string false "The room of the location of the professor's office"
159+ // @Param office.map_uri query string false "A hyperlink to the UTD room locator of the professor's office"
160+ // @Param profile_uri query string false "A hyperlink pointing to the professor's official university profile"
161+ // @Param image_uri query string false "A link to the image used for the professor on the professor's official university profile"
162+ // @Param office_hours.start_date query string false "The start date of one of the office hours meetings of the professor"
163+ // @Param office_hours.end_date query string false "The end date of one of the office hours meetings of the professor"
164+ // @Param office_hours.meeting_days query string false "One of the days that one of the office hours meetings of the professor"
165+ // @Param office_hours.start_time query string false "The time one of the office hours meetings of the professor starts"
166+ // @Param office_hours.end_time query string false "The time one of the office hours meetings of the professor ends"
167+ // @Param office_hours.modality query string false "The modality of one of the office hours meetings of the professor"
168+ // @Param office_hours.location.building query string false "The building of one of the office hours meetings of the professor"
169+ // @Param office_hours.location.room query string false "The room of one of the office hours meetings of the professor"
170+ // @Param office_hours.location.map_uri query string false "A hyperlink to the UTD room locator of one of the office hours meetings of the professor"
171+ // @Param sections query string false "The _id of one of the sections the professor teaches"
172+ // @Success 200 {array} schema.Course "A list of Courses"
173+ func ProfessorCourseSearch () gin.HandlerFunc {
174+ // Wrapper of professorCourse() with flag of Search
175+ return func (c * gin.Context ) {
176+ professorCourse ("Search" , c )
177+ }
178+ }
179+
180+ // @Id professorCourseById
181+ // @Router /professor/{id}/courses [get]
182+ // @Description "Returns all the courses taught by the professor with given ID"
183+ // @Produce json
184+ // @Param id path string true "ID of the professor to get"
185+ // @Success 200 {array} schema.Course "A list of courses"
186+ func ProfessorCourseById () gin.HandlerFunc {
187+ // Essentially wrapper of professorCourse() with flag of ById
188+ return func (c * gin.Context ) {
189+ professorCourse ("ById" , c )
190+ }
191+ }
192+
193+ // Get all of the courses of the professors depending on the type of flag
194+ func professorCourse (flag string , c * gin.Context ) {
195+ ctx , cancel := context .WithTimeout (context .Background (), 10 * time .Second )
196+
197+ var professorCourses []schema.Course // array of courses of the professors (or single professor with Id)
198+ var professorQuery bson.M // query filter the professor
199+ var err error
200+
201+ defer cancel ()
202+
203+ // determine the professor's query
204+ if flag == "Search" { // if the flag is Search, filter professors based on query parameters
205+ // build the key-value pairs of query parameters
206+ professorQuery , err = schema.FilterQuery [schema.Professor ](c )
207+ if err != nil {
208+ c .JSON (http .StatusBadRequest , responses.ErrorResponse {Status : http .StatusBadRequest , Message : "schema validation error" , Data : err .Error ()})
209+ return
210+ }
211+ } else if flag == "ById" { // if the flag is ById, filter that single professor based on their _id
212+ // parse the ObjectId
213+ professorId := c .Param ("id" )
214+ professorObjId , err := primitive .ObjectIDFromHex (professorId )
215+ if err != nil {
216+ log .WriteError (err )
217+ c .JSON (http .StatusBadRequest , responses.ErrorResponse {Status : http .StatusBadRequest , Message : "error" , Data : err .Error ()})
218+ return
219+ }
220+ professorQuery = bson.M {"_id" : professorObjId }
221+ } else {
222+ // something wrong that messed up the server
223+ c .JSON (http .StatusInternalServerError , responses.ErrorResponse {Status : http .StatusInternalServerError , Message : "error" , Data : "Endpoint broken" })
224+ return
225+ }
226+
227+ // determine the offset and limit for pagination stage
228+ // and delete "offset" field in professorQuery
229+ offset , limit , err := configs .GetAggregateLimit (& professorQuery , c )
230+ if err != nil {
231+ log .WriteErrorWithMsg (err , log .OffsetNotTypeInteger )
232+ c .JSON (http .StatusConflict , responses.ErrorResponse {Status : http .StatusConflict , Message : "Error offset is not type integer" , Data : err .Error ()})
233+ return
234+ }
235+
236+ // Pipeline to query the courses from the filtered professors (or a single professor)
237+ professorCoursePipeline := mongo.Pipeline {
238+ // filter the professors
239+ bson.D {{Key : "$match" , Value : professorQuery }},
240+
241+ // paginate the professors before pulling the courses from those professor
242+ bson.D {{Key : "$skip" , Value : offset }}, // skip to the specified offset
243+ bson.D {{Key : "$limit" , Value : limit }}, // limit to the specified number of professors
244+
245+ // lookup the array of sections from sections collection
246+ bson.D {{Key : "$lookup" , Value : bson.D {
247+ {Key : "from" , Value : "sections" },
248+ {Key : "localField" , Value : "sections" },
249+ {Key : "foreignField" , Value : "_id" },
250+ {Key : "as" , Value : "sections" },
251+ }}},
252+
253+ // project the courses referenced by each section in the array
254+ bson.D {{Key : "$project" , Value : bson.D {{Key : "courses" , Value : "$sections.course_reference" }}}},
255+
256+ // lookup the array of courses from coures collection
257+ bson.D {{Key : "$lookup" , Value : bson.D {
258+ {Key : "from" , Value : "courses" },
259+ {Key : "localField" , Value : "courses" },
260+ {Key : "foreignField" , Value : "_id" },
261+ {Key : "as" , Value : "courses" },
262+ }}},
263+
264+ // unwind the courses
265+ bson.D {{Key : "$unwind" , Value : bson.D {
266+ {Key : "path" , Value : "$courses" },
267+ {Key : "preserveNullAndEmptyArrays" , Value : false }, // to avoid the professor documents that can't be replaced
268+ }}},
269+
270+ // replace the combination of ids and courses with the courses entirely
271+ bson.D {{Key : "$replaceWith" , Value : "$courses" }},
272+ }
273+
274+ // Perform aggreration on the pipeline
275+ cursor , err := professorCollection .Aggregate (ctx , professorCoursePipeline )
276+ if err != nil {
277+ // return the error with there's something wrong with the aggregation
278+ log .WriteError (err )
279+ c .JSON (http .StatusInternalServerError , responses.ErrorResponse {Status : http .StatusInternalServerError , Message : "error" , Data : err .Error ()})
280+ return
281+ }
282+ // Parse the array of courses from these professors
283+ if err = cursor .All (ctx , & professorCourses ); err != nil {
284+ log .WritePanic (err )
285+ panic (err )
286+ }
287+ c .JSON (http .StatusOK , responses.MultiCourseResponse {Status : http .StatusOK , Message : "success" , Data : professorCourses })
288+ }
0 commit comments